网络编程五--自定义应用层协议

这篇具有很好参考价值的文章主要介绍了网络编程五--自定义应用层协议。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

前面回声服务器/客户端介绍了如何通过对收发IO的控制实现回声服务器/客户端。

在服务器端应用层的处理(协议)可以看作是“回声操作”,即回发客户端发来的消息。而在客户端应用层的处理(协议)则只是简单显示服务器回发的内容。

而协议的通俗理解,就是为了完成数据交换而定好的约定。

本章将通过一个简单的示例展开,如何"自定义应用层协议"。

自定义应用层协议

首先描述下我们打算实现的简单需求:服务器端要根据客户端发来的数据和运算符进行相应运算,并把结果返回给客户端。

根据上述需求,我们需要自定义的应用层协议内容:
客户端:
①要求用户先输入操作数的数量。
②然后要求用户输入①中数量的具体数值。
③最后要求客户输入运算符
这里均假设用户输入的是一个合理的数量(当然也可进行相应的判断限制)。

输入完成后,一起打包发送给服务器。

服务器:
①按客户端的打包顺序解析接收到的数据。即接收数据的第一个字节大小的内容为操作数数量n,接着的n个字节的内容则为实际操作数数值,而最后一个字节的内容则为运算符。
②根据①中解析得到的内容进行相应运算
③将运算结果返回给客户端

通过规定输入前(客户端的应用层)、输出后(服务器端的应用层)的数据的处理方式,实现自定义的应用层协议。

效果预览

网络编程五--自定义应用层协议
网络编程五--自定义应用层协议
网络编程五--自定义应用层协议
因除法还需对除数进行相应非0判断,因此这里不再处理。

最后给出完整代码。

服务器

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#define BUF_SIZE 1024
#define OPSZ 4

int calculate(int opnum, int opnds[], char op)
{
	int result = opnds[0], i;

	printf("操作数数量: %d, 第一个操作数: %d, 操作符: %c\n", opnum, result, op);

	switch(op)
	{
	case '+':
		for (i = 1; i < opnum; i++)
		{
			result += opnds[i];
		}
		break;

	case '-':
		for (i = 1; i < opnum; i++)
		{
			result -= opnds[i];
		}
		break;

	case '*':
		for (i = 1; i < opnum; i++)
		{
			result *= opnds[i];
		}
		break;

	default:
		for (i = 1; i < opnum; i++)
		{
			result += opnds[i];
		}
		break;
	}

	return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc != 2)
	{
		printf("arg error!");
		return -1;
	}

	WSADATA wsaData;
	if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
	{
		printf("WSAStartup error!");
		return -1;
	}

	SOCKET srvSock = socket(PF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == srvSock)
	{
		printf("socket error!");
		WSACleanup();
		return -1;
	}

	SOCKADDR_IN srvAddr;
	memset(&srvAddr, 0, sizeof(srvAddr));
	srvAddr.sin_family = PF_INET;
	srvAddr.sin_addr.s_addr = htonl(ADDR_ANY);
	srvAddr.sin_port = htons(_ttoi(argv[1]));

	if (SOCKET_ERROR == bind(srvSock, (sockaddr*)&srvAddr, sizeof(srvAddr)))
	{
		printf("bind error!");
		closesocket(srvSock);
		WSACleanup();
		return -1;
	}
	
	if (SOCKET_ERROR == listen(srvSock, 5))
	{
		printf("listen error!");
		closesocket(srvSock);
		WSACleanup();
		return -1;
	}

	SOCKADDR_IN cltAddr;
	memset(&cltAddr, 0, sizeof(cltAddr));
	int cltAddrLen = sizeof(cltAddr);

	int opnd_cnt = 0;

	int recvLen = 0;
	char Msg[BUF_SIZE];
	int result = 0;
	for (int i = 0; i < 5; i++)
	{
		printf("Wait client Connect...\n");
		opnd_cnt = 0;
		SOCKET cltSock = accept(srvSock, (sockaddr*)&cltAddr, &cltAddrLen);
		if (INVALID_SOCKET == cltSock)
		{
			printf("accept error!");
			closesocket(srvSock);
			WSACleanup();
			return -1;
		}

		printf("Client %d Connected.\n", i + 1);

		//得到操作数量
		recv(cltSock, (char*)&opnd_cnt, 1, 0);

		recvLen = 0;
		while ( (opnd_cnt * OPSZ + 1) > recvLen )
		{
			int recv_cnt = recv(cltSock, &Msg[recvLen], BUF_SIZE - 1, 0);
			recvLen += recv_cnt;
		}
		
		printf("接收长度: %d, 操作符: %c\n", recvLen, Msg[recvLen - 1]);
		
		//printf("Msg: %s\n", Msg);
		result  = calculate(opnd_cnt, (int*)Msg, Msg[recvLen - 1]);
		send(cltSock, (char*)&result, sizeof(result), 0);

		closesocket(cltSock);
	}

	closesocket(srvSock);
	WSACleanup();

	return 0;
}

客户端

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#define BUF_SIZE 1024
#define OPSZ 4
#define RLT_SIZE 4

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc != 3)
	{
		printf("arg error!");
		return -1;
	}

	WSADATA wsaData;
	if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
	{
		printf("WSAStartup error!");
		return -1;
	}

	SOCKET srvSock = socket(PF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == srvSock)
	{
		printf("socket error!");
		WSACleanup();
		return -1;
	}


	SOCKADDR_IN srvAddr;
	memset(&srvAddr, 0, sizeof(srvAddr));

	srvAddr.sin_family = PF_INET;
	srvAddr.sin_addr.s_addr = inet_addr(argv[1]);
	srvAddr.sin_port = htons(_ttoi(argv[2]));
	int srvAddrLen = sizeof(srvAddr);

	if (SOCKET_ERROR == connect(srvSock, (sockaddr*)&srvAddr, srvAddrLen))
	{
		printf("connect error!");
		closesocket(srvSock);
		WSACleanup();
		return -1;
	}

	printf("Connected...");

	int opnd_cnt = 0;
	fputs("操作数数量: ", stdout);
	scanf("%d", &opnd_cnt);

	char Msg[BUF_SIZE];
	Msg[0] = (char)opnd_cnt;

	for (int i = 0; i < opnd_cnt; i++)
	{
		printf("操作数: ", stdout);
		scanf("%d", (int*)&Msg[i * OPSZ + 1]);
	}

	//清除输入缓存
	fgetc(stdin);

	fputs("操作符: ", stdout);
	scanf("%c", &Msg[opnd_cnt * OPSZ + 1]);

	printf("Send to Server: %c\n", Msg[opnd_cnt * OPSZ + 1]);
	send(srvSock, Msg, opnd_cnt * OPSZ + 2, 0);
	
	int result = 0;
	recv(srvSock, (char*)&result, RLT_SIZE, 0);

	printf("操作结果: %d\n", result);
	closesocket(srvSock);
	WSACleanup();

	getchar();
	getchar();

	return 0;
}


总结

本章通过一个简单的运算示例介绍如何自定义应用层协议,所谓的协议就是为了完成数据交换而定好的约定,只不过这里的约定应用在了应用层,即输入前(客户端的应用层)、输出后(服务器端的应用层)的数据的处理方式。

万变不离其宗,后续若碰到类似需求,也可按实际情况扩展即可。文章来源地址https://www.toymoban.com/news/detail-437249.html

到了这里,关于网络编程五--自定义应用层协议的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 谈谈linux网络编程中的应用层协议定制、Json序列化与反序列化那些事

    由于socket api的接口,在读写数据的时候是以字符串的方式发送接收的,如果需要传输 结构化的数据 ,就需要制定一个协议 结构化数据在发送到网络中之前需要完成序列化 接收方收到的是序列字节流,需要完成反序列化才能使用(如ChatInfo._name) 当我们进行网络通信的的时

    2024年02月06日
    浏览(48)
  • 网络编程:TCP粘包问题——各层粘包/拆包、Nagle 算法、Go实现长度字段协议解决TCP粘包、使用TCP的应用层协议设计

    1.1 TCP介绍 如上图,TCP具有面向连接、可靠、基于字节流三大特点。 字节流可以理解为一个双向的通道里流淌的数据,这个数据其实就是我们常说的二进制数据,简单来说就是一大堆 01 串。纯裸TCP收发的这些 01 串之间是没有任何边界的,你根本不知道到哪个地方才算一条完

    2024年02月04日
    浏览(24)
  • 根据源码,模拟实现 RabbitMQ - 网络通讯设计,自定义应用层协议,实现 BrokerServer (8)

    目录 一、网络通讯协议设计 1.1、交互模型 1.2、自定义应用层协议 1.2.1、请求和响应格式约定 ​编辑 1.2.2、参数说明 1.2.3、具体例子 1.2.4、特殊栗子 1.3、实现 BrokerServer 1.3.1、属性和构造 1.3.2、启动 BrokerServer 1.3.3、停止 BrokerServer 1.3.4、处理每一个客户端连接 1.3.5、读取请求

    2024年02月10日
    浏览(27)
  • 【JavaEE】应用层自定义协议及UDP协议

    博主简介:想进大厂的打工人 博主主页: @xyk: 所属专栏: JavaEE初阶 本篇文章将为大家介绍应用层中UDP协议~~ 在应用层这里,虽然存在一些现有的协议(HTTP),但是也有很多情况,需要程序猿自定制协议,对于自定制协议来说,就是个很简单的事情~~那么怎么理解这件事情?

    2024年02月06日
    浏览(25)
  • 【网络】应用层——HTTPS协议

    🐱作者:一只大喵咪1201 🐱专栏:《网络》 🔥格言: 你只管努力,剩下的交给时间! 前面本喵讲解并演示了HTTP协议,在比较 POST 和 GET 方法的时候,本喵说这两个方法都不安全,虽然 POST 的提交的表单内容在请求正文中,无法在地址的 url 中看到,但是它仍然是不安全的。

    2024年02月14日
    浏览(27)
  • 【网络】应用层——HTTP协议

    🐱作者:一只大喵咪1201 🐱专栏:《网络》 🔥格言: 你只管努力,剩下的交给时间! 上篇文章中,本喵带着大家对HTTP有了一个初步的认识,今天就来详细讲解一下这个应用层协议。 如上图所示的 url (网址),里面包含有 / 以及 ? 等字符。 像这样的字符,已经被url当做 特殊

    2024年02月15日
    浏览(23)
  • 【网络原理】应用层协议 与 传输层协议

    ✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 我们自己写的应用程序就是在应用层 虽然应用层里面有一些现成的协议,但是在实际工作中也会存在 自定义应用层协议 (发明协议? 协议就是约定,约定好客户端和服务器按照啥样的格式来传输数据 ) 那么应用层协议如何

    2023年04月20日
    浏览(37)
  • 网络安全——应用层安全协议

    作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。   座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录  前言 一.应用层安全协议  1.应用层安全威胁 2.电子邮件安全协议 1.MIME协议 2.电子邮件安全威胁  3.S/MIME协议 4.PGP协议 本

    2024年02月06日
    浏览(43)
  • 网络协议(七)应用层-HTTP

    上篇文章介绍了传输层的TCP、UDP协议,在TCP/IP协议中,下三层(网络接口层,网络层,传输层)都是计算机系统联合其他硬件设备自己在干的事,身为程序员的我们平时对其感知不大。而应用层却是与程序开发息息相关的一层,如HTTP,HTTPS,DNS,FTP,SMTP等等,针对不同应用场

    2024年02月03日
    浏览(26)
  • 【计算机网络】应用层协议 -- HTTP协议

    协议。网络协议的简称,网络协议是通信计算机双方必须共同遵守的一组约定,比如怎么建立连接,怎么互相识别等。 为了使数据在网络上能够从源头到达目的,网络通信的参与方必须遵守相同的规则,我们称这套相同的规则为协议(protocol),而协议最终都需要通过计算机

    2024年02月15日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包