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粘包分析与处理相关推荐

  1. TCP粘包以及粘包处理

    TCP粘包现象 TCP粘包通俗来讲,就是发送方发送的多个数据包,到接收方后粘连在一起,导致数据包不能完整的体现发送的数据. TCP粘包原因分析 导致TCP粘包的原因,可能是发送方的原因,也有可能是接受 ...

  2. TCP粘包问题分析和解决(全)

    TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...

  3. 【Netty】入门Netty官方例子解析(三)处理一个基于流的传输 TCP粘包和拆包问题分析和解决

    关于 Socket Buffer的一个小警告 基于流的传输比如 TCP/IP, 接收到数据是存在 socket 接收的 buffer 中.不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列. ...

  4. Netty(二)——TCP粘包/拆包

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7814644.html 前面讲到:Netty(一)--Netty入门程序 主要内容: TCP粘包/拆包的基础知 ...

  5. 【Netty入门】TCP 粘包/拆包问题产生原因

    TCP粘包/分包问题的由来 因为TCP是以流的方式来处理数据,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送. 这样说可能比较抽象,下面举例来说明TCP拆包/粘包 ...

  6. Netty学习总结(5)——Netty之TCP粘包/拆包问题的解决之道

    无论是服务端还是客户端,读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议. 流:没有界限的一串数据.如同河里的流水,它们是连成 ...

  7. 20-Netty TCP 粘包和拆包及解决方案

    TCP粘包和拆包的基本介绍 TCP是面向连接的, 面向流的, 提供可靠性服务, 收发两端(客户端和服务器端) 都有一一成对的Socket,因此发送端为了将多个发给接收端的包, 更有效的发给对方, 使用 ...

  8. TCP粘包/拆包问题

    目录 TCP粘包/拆包 TCP粘包/拆包问题说明 TCP粘包/拆包发生的原因 粘包问题的解决策略 未考虑TCP粘包导致功能异常案例  TimeServer的改造 TimeClient的改造 利用Lin ...

  9. TCP粘包问题以及解决方法

    粘包问题分析与对策 TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾. 出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方 ...

  10. tcp 粘包 丢包 解决方案

    1.分析tcp粘包和丢包的原因 发送数据的时候有  发送缓冲区senBuff, 接收数据的时候有  接收缓冲区recvBuff, 假如接收数据方一直不recv, 则recvBuff就会堆满, 这个时候 ...

最新文章

  1. html表格鼠标高亮行列,JS实现的表格行鼠标点击高亮效果代码
  2. linux dmesg命令参数及用法详解(linux显示开机信息命令)
  3. 国产知名老牌 PDF 工具正式开源
  4. 统计百度网盘文件个数 V3
  5. 电脑显示器不亮主机正常_电脑主机已开机 显示屏却不亮(看完秒懂)
  6. 微软请你学Linux,你没有听错,是Linux系列培训4月~6月,共16期,4月5日起盛情开始!微软请你!!!
  7. the deep ritz method论文梳理
  8. JRuby 1.6.5发布 Ruby语言的Java实现
  9. PotPlayer 禁止更新
  10. java 配置文件参数_从Java的配置文件中读取配置参数的最佳方法是什么?
  11. 敏捷软件开发与极限编程
  12. 语音芯片c语言程序,51单片机 语音芯片YF017 驱动函数以及简单调用例程
  13. python爬虫获取数据失败请稍后访问_Python爬取微博评论数据,竟被反爬封号了!...
  14. 使用github下载项目压缩包,打开前端项目加载依赖报错。
  15. RTX 30系列性能≥2倍图灵GPU!AI算力前瞻,性价比超泰坦
  16. python中ipaddress库用法详解
  17. java jsoup解析开彩网api接口json数据实例
  18. P2597 [ZJOI2012]灾难(支配树)
  19. RK3368 Edp屏调试,利用EDID做兼容
  20. new(创建)一个对象时都发生了什么?

热门文章

  1. linux操作系统安装教程图解【图文教程】
  2. BT5的默认用户名和密码
  3. MinGW-w64 离线包安装方法
  4. Flash学习资源下载列表
  5. php实现酒店客房管理系统,基于ssh/jsp/java/asp.net/php的酒店客房管理系统
  6. 【VB.NET视频总结(一)】
  7. 基于竞争的MAC协议
  8. SpringBoot利用ELK实现日志收集
  9. Android 打造万能网络解析框架
  10. Java io流使用相对路径读取文件