ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Tcp流式传输解决粘包和少包的方案

2021-07-02 11:33:05  阅读:185  来源: 互联网

标签:head 字节 tmpbuffer sendData Tcp 粘包 char 少包 消息


tcp是流式传输协议,接收端和发送端的 收发时间延时,此时会出现粘包现象

比如:再不考虑内核双向缓冲区的延时发送问题,客户端假设1s 发送100k,循环发,服务器每2s收一次数据,此时服务器收到了200k,出现了消息粘包,服务器也不知道客户端的消息分组情况,所以我们需要和客户端协商一个解决方案,类型tcp底层封装思想一下定义为 消息头和消息体:
下面伪代码展示一下:

发送端:

void sendMsg(int fd, char* sendData)
{
	/*这里的sendData数据体他是字符串形式的 不需要考虑字节对齐问题,
	sendData处理后的数据我们可以通过protobuf工具进行序列化得到一个字符串
	*/
	//在每条消息发送前面我们和服务器协商好定义一个int类型4字节的消息头里面存储消息实际长度
	int allLen = strlen(sendData) + 4;  //要发送的消息总长度  4就是消息头的大小,内容是要发送实际数据
	char* netData = new char[allLen]; //一条完整消息 包含消息体和消息头
	memset(netData, 0 sizeof(netData));
	uint32_t head = strlen(sendData);  //头保存消息体数据长度
	//int 是4字节的数据 由于不同机器要考虑到网络传输的字节对齐问题,而字符串不用考虑,所以需要将主机字节序转换为网络字节序
	head = htonl(head);  //head 对应4字节所以用 htohl()
	
	memstrcpy(netData , &head, 4);  //将消息头数据先拷贝要发送的数据包里面
	//然后将消息体实际数据拷贝发送包里面
	memstrcpy(netData +4, sendData, strlen(sendData));
	
	send(fd, netData, allLen, 0); //将数据发送给接收端
}

接收端:

#define RECVSIZE  40960000
char tmpbuffer[RECVSIZE] = {0};  //超大缓冲区  
void recvMsg(fd, char* recvData)
{
	 //这里准确的做法是应该用个缓冲区一次性接收所有数据 防止的不完整

	 int len = recv(fd, tmpbuffer+strlen(tmpbuffer), 40960000, 0) //这里tmpbuffer+strlen(tmpbuffer) 因为有没有满足一条完整消息 而留下的数据此时要接着缓冲区后面的位置继续写
	 if( len > 4)  //>4先取头信息 看消息体长度够不够
	 {
	  	uint32_t head = 0;
		memstrcpy(&head, tmpbuffer, 4)
		head = ntohl(head);  //将读到的数据网络字节序转换为本机字节序 head 里面的大小就是消息体内容的长度
		int readLen = 0  //已经读取的数据
		while(true)   //通过循环将消息拆分一条条处理完
		{
			if(len >= head + 4)  //满足一条完整的数据, 拆包过程
			{
				char* lineData = new char[head]
				readLen + = 4 //如果满足了head + 4 <= len 才可以设置readLen加,要不然丢失头数据信息
				memstrcpy(lineData, tmpbuffer+readLen , head) //取数据从缓冲区的头依次取数据
				readLen += head   //4+head 读走了一条完整数据的长度
				len -= readLen    //剩下的数据长度
				//将lineData通过protocol反序列化
				//处理对应得了逻辑
				delete [] lineData;
				lienData = NULL; 
			}
			else //不满足一条完整的数据
			{
				memstrcpy(tmpbuffer, tmpbuffer+readLen, len-readLen); //这里将剩下数据拷回临时缓冲区起始地址
				tmpbuffer[readLen+1] = '\0';   //strlen 遇到\0停止
				break;
			}
			memstrcpy(&head, tmpbuffer+readLen , 4)
			head = ntohl(head);  //将读到的数据网络字节序转换为本机字节序 head 里面的大小就是消息体内
			
		}
	 }
}

标签:head,字节,tmpbuffer,sendData,Tcp,粘包,char,少包,消息
来源: https://blog.csdn.net/qq_22203741/article/details/118408616

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有