TCP粘包分析与处理
TCP粘包现象
TCP粘包通俗来讲,就是发送方发送的多个数据包,到接收方后粘连在一起,导致数据包不能完整的体现发送的数据。
TCP粘包原因分析
导致TCP粘包的原因,可能是发送方的原因,也有可能是接受方的原因。
发送方
由于TCP需要尽可能高效和可靠,所以TCP协议默认采用Nagle算法,以合并相连的小数据包,再一次性发送,以达到提升网络传输效率的目的。但是接收方并不知晓发送方合并数据包,而且数据包的合并在TCP协议中是没有分界线的,所以这就会导致接收方不能还原其本来的数据包。
接收方
TCP是基于“流”的。网络传输数据的速度可能会快过接收方处理数据的速度,这时候就会导致,接收方在读取缓冲区时,缓冲区存在多个数据包。在TCP协议中接收方是一次读取缓冲区中的所有内容,所以不能反映原本的数据信息。
解决TCP粘包
分析了产生TCP粘包的原因之后,针对发生的原因,针对性的采取解决方法。
禁用Negle算法
因为TCP协议采用Negle算法,导致粘包。所以可以禁用Nagle算法。
const char chOpt = 1;
int nErr = setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char)); if(nErr == -1) { TRACE( "setsockopt() error\n", WSAGetLastError()); return ; }
这种方法虽然能一定程度上解决TCP粘包,但是并不能完全解决问题。因为接收方也是可能造成粘包的原因,这种方法只是发送方有效。而且禁用Nagle算法,一定程度上使TCP传输效率降低了。所以,这并不是一种理想的方法。
PUSH标志
PUSH是TCP报头中的一个标志位,发送方在发送数据的时候可以设置这个标志位。该标志通知接收方将接收到的数据全部提交给接收进程。这里所说的数据包括与此PUSH包一起传输的数据以及之前就为该进程传输过来的数据。
当Server端收到这些数据后,它需要立刻将这些数据提交给应用层进程,而不再等待是否还有额外的数据到达。
设置PUSH标志也不能完全解决TCP粘包,只是降低了接收方粘包的可能性。实际上现在的TCP协议栈基本上都可以自行处理这个问题,而不是交给应用层处理。所以设置PUSH标志,也不是一种理想的方法。
自定协议
自定协议,将数据包分为了封包和解包两个过程。在发送方发送数据时,对发送的数据进行封包操作。在接收方接收到数据时对接收的数据包需要进行解包操作。
自定协议时,封包就是为发送的数据增加包头,包头包含数据的大小的信息,数据就跟随在包头之后。当然包头也可以有其他的信息,比如一些做校验的信息。这里主要讨论TCP粘包的问题,所以不考虑其他的。
发送方封包
PACKAGE_HEAD pPackageHead; //PACKAGE_HEAD 包头结构体
char PackageHead[1024];
int headLen = sizeof(PACKAGE_HEAD); int packgeContextLen = strlen(packageContext); //packageContext 发送的数据 pPackageHead->nDataLen = packgeContextLen; //包的大小 char *packge = (char*)malloc(headLen + packgeContextLen); //包的内存分配 memset(packge, 0, headLen + packgeContextLen); char *packgeCpy = (char*)memcpy(packge, (char*)&pPackageHead, headLen);//拷贝包头 packgeCpy += headLen; packge = (char*)memcpy(packgeCpy, (char*)&packageContext, packgeContextLen);//拷贝包内容 int ret = 0; ret = send(m_hSocket, packge, headLen + packgeContextLen, 0); //发送包 if (ret == SOCKET_ERROR || ret == 0) { return ret; }
接收方解包
char PackageHead[1024];
char PackageContext[1024*20]; int len; PACKAGE_HEAD *pPackageHead; //PACKAGE_HEAD 包头结构体 while( m_bClose == false ) { memset(PackageHead, 0, sizeof(PACKAGE_HEAD)); len = ReceiveSize(m_TcpSock, (char*)PackageHead, sizeof(PACKAGE_HEAD)); //接收包头 if( len == SOCKET_ERROR ) { break; } if(len == 0) { break; } pPackageHead = (PACKAGE_HEAD *)PackageHead; memset(PackageContext,0,sizeof(PackageContext)); if(pPackageHead->nDataLen>0) //根据包头中的数据长度,接收数据 { len = ReceiveSize(m_TcpSock, (char*)PackageContext,pPackageHead->nDataLen); } }
接收指定长度的数据函数
//接收指定长度的数据
int ReceiveSize(SOCKET m_hSocket, char* strData, int gLen) { if(strData == NULL) return ERR_BADPARAM; char *p = strData; int len = gLen; int ret = 0; int returnlen = 0; while( len > 0) { ret = recv( m_hSocket, p+(iLen-len), iLen-returnlen, 0); if (ret == SOCKET_ERROR || ret == 0) { return ret; } len -= ret; returnlen += ret; } return returnlen; }
这样就可以达到解决TCP粘包的问题。在实际使用中包头还带有更多的信息,而且包尾可能还会带上分隔符,在redis、FTP中就是这样处理的。
UDP不存在粘包
由于UDP不是面向‘流’的,而且UDP是具有消息边界的。也就是说UDP的发送的每一个数据包都是独立的。所以UDP并不存在粘包的问题。
TCP粘包分析与处理相关推荐
- TCP粘包以及粘包处理
TCP粘包现象 TCP粘包通俗来讲,就是发送方发送的多个数据包,到接收方后粘连在一起,导致数据包不能完整的体现发送的数据. TCP粘包原因分析 导致TCP粘包的原因,可能是发送方的原因,也有可能是接受 ...
- TCP粘包问题分析和解决(全)
TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...
- 【Netty】入门Netty官方例子解析(三)处理一个基于流的传输 TCP粘包和拆包问题分析和解决
关于 Socket Buffer的一个小警告 基于流的传输比如 TCP/IP, 接收到数据是存在 socket 接收的 buffer 中.不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列. ...
- Netty(二)——TCP粘包/拆包
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7814644.html 前面讲到:Netty(一)--Netty入门程序 主要内容: TCP粘包/拆包的基础知 ...
- 【Netty入门】TCP 粘包/拆包问题产生原因
TCP粘包/分包问题的由来 因为TCP是以流的方式来处理数据,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送. 这样说可能比较抽象,下面举例来说明TCP拆包/粘包 ...
- Netty学习总结(5)——Netty之TCP粘包/拆包问题的解决之道
无论是服务端还是客户端,读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议. 流:没有界限的一串数据.如同河里的流水,它们是连成 ...
- 20-Netty TCP 粘包和拆包及解决方案
TCP粘包和拆包的基本介绍 TCP是面向连接的, 面向流的, 提供可靠性服务, 收发两端(客户端和服务器端) 都有一一成对的Socket,因此发送端为了将多个发给接收端的包, 更有效的发给对方, 使用 ...
- TCP粘包/拆包问题
目录 TCP粘包/拆包 TCP粘包/拆包问题说明 TCP粘包/拆包发生的原因 粘包问题的解决策略 未考虑TCP粘包导致功能异常案例 TimeServer的改造 TimeClient的改造 利用Lin ...
- TCP粘包问题以及解决方法
粘包问题分析与对策 TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾. 出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方 ...
- tcp 粘包 丢包 解决方案
1.分析tcp粘包和丢包的原因 发送数据的时候有 发送缓冲区senBuff, 接收数据的时候有 接收缓冲区recvBuff, 假如接收数据方一直不recv, 则recvBuff就会堆满, 这个时候 ...
最新文章
- html表格鼠标高亮行列,JS实现的表格行鼠标点击高亮效果代码
- linux dmesg命令参数及用法详解(linux显示开机信息命令)
- 国产知名老牌 PDF 工具正式开源
- 统计百度网盘文件个数 V3
- 电脑显示器不亮主机正常_电脑主机已开机 显示屏却不亮(看完秒懂)
- 微软请你学Linux,你没有听错,是Linux系列培训4月~6月,共16期,4月5日起盛情开始!微软请你!!!
- the deep ritz method论文梳理
- JRuby 1.6.5发布 Ruby语言的Java实现
- PotPlayer 禁止更新
- java 配置文件参数_从Java的配置文件中读取配置参数的最佳方法是什么?
- 敏捷软件开发与极限编程
- 语音芯片c语言程序,51单片机 语音芯片YF017 驱动函数以及简单调用例程
- python爬虫获取数据失败请稍后访问_Python爬取微博评论数据,竟被反爬封号了!...
- 使用github下载项目压缩包,打开前端项目加载依赖报错。
- RTX 30系列性能≥2倍图灵GPU!AI算力前瞻,性价比超泰坦
- python中ipaddress库用法详解
- java jsoup解析开彩网api接口json数据实例
- P2597 [ZJOI2012]灾难(支配树)
- RK3368 Edp屏调试,利用EDID做兼容
- new(创建)一个对象时都发生了什么?