1、粘包的概念

粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

比如说:发送方发送了两个数据,接收方一次收了一个半数据(接收方可能不清楚一个包有多大)

2、tcp,udp报文最大长度

ip报文:

tcp报文:

udp报文:

ip和udp都有16位的长度字段,理论上ip和udp报文的最大负载长度应该为2^16,64KB,而tcp没有长度字段,理论上应该和ip一样。
但是存在其他限制
网络层限制:MTU(Maximum Transmission Unit,最大传输单元),这限制了ip报文长度,ip报文长度大于mtu,就需要分片。通常设为1500字节。
传输层限制:tcp协议中有个MSS(最大报文长度),tcp通常将数据分成长度为MSS的若干块。通常为MTU(1500)-IP数据包包头(20)-TCP数据段的包头(20)=1460字节。
所以tcp一次传输数据应该最大有1460字节。

3、出现粘包的原因

出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。

发送方引起的粘包是由TCP协议本身造成的:

  • TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
  • TCP协议规定有MSS,如果数据包过长就会被分开传输。这样接收方就收到了粘包数据。

接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。

在代码中常见体现:

  1. 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
  2. 要发送的数据大于MSS,TCP在传输前将进行拆包。
  3. 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
  4. 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
    等等。

4、粘包的处理方式:

  1. 当时短连接的情况下,不用考虑粘包的情况
  2. 如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
  3. 如果双方建立长连接,需要在连接后一段时间内发送不同结构数据
    • 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
    • 发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
    • 可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
      等等。

在网课学习中看到的指定数据长度的解决方法,主要思路:
我们在数据结构中有个成员代表了长度(消息头),我们准备一个足够大的消息缓冲区(程序中是1024000个字节),循环使用socket中的recv每次读取最多102400个字节,然后把循环接收的消息拼接到消息缓冲区中,直到接收到的消息大于消息头指示的长度,则接收到了一个完整的消息(所以我们的消息缓冲区要比完整的消息还要大才行),进行消息处理。

主要代码:

// 缓冲区最小单元大小
#ifndef RECV_BUFF_SZIE
#define RECV_BUFF_SZIE 102400
#endif // !RECV_BUFF_SZIE
// 第二缓冲区 消息缓冲区
char _szMsgBuf[RECV_BUFF_SZIE * 10] = {};
// 消息缓冲区的数据尾部位置
int _lastPos = 0;
// 接收缓冲区
char _szRecv[RECV_BUFF_SZIE] = {};// 接收数据 处理粘包 拆分包
int RecvData(SOCKET cSock)
{// 5 接收数据int nLen = (int)recv(cSock, _szRecv, RECV_BUFF_SZIE, 0);//printf("nLen=%d\n", nLen);if (nLen <= 0){printf("<socket=%d>与服务器断开连接,任务结束。\n", cSock);return -1;}// 将收取到的数据拷贝到消息缓冲区memcpy(_szMsgBuf+_lastPos, _szRecv, nLen);// 消息缓冲区的数据尾部位置后移_lastPos += nLen;// 判断消息缓冲区的数据长度大于消息头DataHeader长度while (_lastPos >= sizeof(DataHeader)){// 这时就可以知道当前消息的长度DataHeader* header = (DataHeader*)_szMsgBuf;// 判断消息缓冲区的数据长度大于消息长度if (_lastPos >= header->dataLength){// 消息缓冲区剩余未处理数据的长度int nSize = _lastPos - header->dataLength;// 处理网络消息OnNetMsg(header);// 将消息缓冲区剩余未处理数据前移memcpy(_szMsgBuf, _szMsgBuf + header->dataLength, nSize);// 消息缓冲区的数据尾部位置前移_lastPos = nSize;}else{//消息缓冲区剩余数据不够一条完整消息break;}}return 0;
}

可运行程序

百度云链接:https://pan.baidu.com/s/1D4VsM2TGIsGUa8tO9p5x5w
提取码:fk5m

TCP粘包原因及解决办法相关推荐

  1. TCP丢包原因、解决办法

    TCP是基于不可靠的网络实现可靠的传输,肯定也会存在掉包的情况,如果通信中发现缺少数据或者丢包,那么,最大的可能在于程序发送的过程或者接收的过程出现问题. 例如服务端要给客户端发送大量数据,Send频 ...

  2. socket Php 粘包,python3 tcp的粘包现象和解决办法解析

    这篇文章主要介绍了python3 tcp的粘包现象和解决办法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 服务器端 import socket ...

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

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

  4. Socket编程实践(5) --TCP粘包问题与解决

    TCP粘包问题 由于TCP协议是基于字节流且无边界的传输协议, 因此很有可能产生粘包问题, 问题描述如下 对于Host A 发送的M1与M2两个各10K的数据块, Host B 接收数据的方式不确定, ...

  5. tcp粘包及如何解决

    1. 什么是粘包 流式套接字 首先说说TCP为什么叫流式套接字,顾名思义,是指TCP的数据传输跟流动的水一样,大家可以想象一下,水是连成一片的,它是没有分界线的,而TCP数据传输也是一样的,是没有界限 ...

  6. TCP粘包,拆包及解决方法、丢包的原因及解决办法

    参考此博客https://blog.insanecoder.top/tcp-packet-splice-and-split-issue/ 粘包.拆包发生原因 发生TCP粘包或拆包有很多原因,现列出常见 ...

  7. 丢包、拆包、粘包的原因及解决办法

    参考此博客https://blog.insanecoder.top/tcp-packet-splice-and-split-issue/ 粘包.拆包发生原因  发生TCP粘包或拆包有很多原因,现列出常 ...

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

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

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

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

  10. Netty解决TCP粘包/拆包导致的半包读写问题

    一.TCP粘包/拆包问题说明 TCP是个"流"协议,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包拆分,所以在业务上认为,一 ...

最新文章

  1. java 日志_跟着Tomcat学编码:Java 原生日志框架分析
  2. 分子特征数据库R包msigdb
  3. iOS enum 定义与使用
  4. 你人脉网中应该有的10种人
  5. TypeScript Downleveling - 什么是 TypeScript 的降级行为
  6. [LeetCode] 547. Friend Circles Java
  7. 爬虫那些事儿-- 简介
  8. 统计在从1到n的正整数中1出现的次数
  9. html字居右垂直设置,css文字水平垂直居中怎么设置?
  10. C语言编译器不检查数组下标越界
  11. 【报告分享】2021快手内容生态半年报:从心出发.pdf(附下载链接)
  12. 黑马博客——详细步骤(六)项目功能的实现之用户信息删除
  13. java数组元素的默认值_数组元素默认的初始值都是什么?
  14. 红帽linux考证时间,红帽认证考试时间
  15. python词云图详细教程
  16. Go:http request cancelled 服务端感知
  17. 听说你要找前端工作,写一个酷炫的动画的简历呀
  18. 【新手村专属】亚太杯数模参赛经验
  19. 淘宝/天猫采集商家信息插件
  20. uniapp 生成商品海报并分享保存

热门文章

  1. 实战Flash游戏开发
  2. 关于优化云成本,你应该知道的事
  3. mysql酒店客房管理系统的设计_《酒店客房管理系统设计》总结
  4. 小米4刷魅族系统后无服务器,小米4线刷魅族Flyme OS系统的教程_小米4 Flyme OS刷机包...
  5. 关于QComboBox
  6. idea简单破解方式
  7. 大华事件检测智能服务器,大华股份发布全新智能视频监控服务器,提供高达768Mbps的存储带宽...
  8. 模糊聚类及matlab实现,matlab模糊聚类程序
  9. 遗传算法的基本原理和matlab实现
  10. oppo android root工具箱,oppo R11(全网通 安卓8.1)手机完美获取root教程,最强root工具,亲测可用!...