一:通过图解法来描述一下分包和粘包,这样客户更清晰直观的了解:

下面对上面的图进行解释: 
1.正常情况:如果Socket Client 发送的数据包,在Socket Server端也是一个一个完整接收的,那个就不会出现粘包和分包情况,数据正常读取。 
2.粘包情况:Socket Client发送的数据包,在客户端发送和服务器接收的情况下都有可能发送,因为客户端发送的数据都是发送的一个缓冲buffer,然后由缓冲buffer最后刷到数据链路层的,那么就有可能把数据包2的一部分数据结合数据包1的全部被一起发送出去了,这样在服务器端就有可能出现这样的情况,导致读取的数据包包含了数据包2的一部分数据,这就产生粘包,当然也有可能把数据包1和数据包2全部读取出来。 
3.分包情况:意思就是把数据包2或者数据包1都有可能被分开一部分发送出去,接着发另外的部分,在服务器端有可能一次读取操作只读到一个完整数据包的一部分。 
4.在数据包发送的情况下,有可能后面的数据包分开成2个或者多个,但是最前面的部分包,黏住在前面的一个完整或者部分包的后面,也就是粘包和分包同时产生了。

二:产生上情况的内部原因有下面几点: 
1.数据发送端发送数据给缓冲buffer太大,导致发送一个完整的数据包被分几次发送给缓存buffer,然而缓冲buffer等到数据满了以后会自动把数据发送的数据链路层去,这样就导致分包了。 
2.TCP协议定义有一个选项叫做最大报文段长度(MSS,Maximum Segment Size),该选项用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度。在一定程度上MSS应该能尽可能多地承载用户数据,用于在传输通路上又可能避免分片,但是在复杂的网络环境下确定这个长度值非常困难,那么在这样的情况下在传输过程中产生分包,粘包就很常见了 
3.以太网,IP,TCP,UDP数据包分析大家可以仔细圆研究这篇文章http://www.cnblogs.com/feitian629/archive/2012/11/16/2774065.html 
4.数据帧的有效载荷(payload)比以太网的最大传输单元(MTU)大的时候,进行了IP分片。

三:解决数据分包和粘包的基本策略如下 
1.消息定长,比如定一个100,那么读取端每次读取数据就截取100个长度的数据,然后交给业务成去做解析 
2.在消息的尾部加一些特殊字符,那么在读取数据的时候,只要读到这个特殊字符,就认为已经可以截取一个完整的数据包了,这种情况在一定的业务情况下实用。 
3.读取缓存的数据是不定长的,所以我们把读取到的数据添加到我们自己的一个byte[]数组中,然后根据我们的业务逻辑来找到指定的特殊协议头部,协议长度,协议尾部,然后从我们的byte[]中获取一个完整的数据包,然后再对数据包进行业务解析就可以得到正确结果。

这里我取其中一种方法(方法3)在这里详细介绍一下:

首先将我们要发送的消息重新封装一下

namespace Tcp客户端
{class Message{public  byte[] SendData(byte[] message){MemoryStream memoryStream = new MemoryStream();//创建一个内存流byte[] BagHead = BitConverter.GetBytes(message.Length + 4);//往字节数组中写入包头(包头自身的长度和消息体的长度)的长度memoryStream.Write(BagHead,0, BagHead.Length);//将包头写入内存流memoryStream.Write(message, 0, message.Length);//将消息体写入内存流byte[] HeadAndBody = memoryStream.ToArray();//将内存流中的数据写入字节数组memoryStream.Close();//关闭内存memoryStream.Dispose();//释放资源return HeadAndBody;}

当消息发送出去后,接收数据时就要解析数据

namespace TCP服务器
{class Messge{MemoryStream memoryStream = new MemoryStream();//开辟一个内存流public void ReceiveData(byte[]receivedata,int receiveLength){memoryStream.Write(receivedata,0, receiveLength);//将接受到的数据写入内存流中byte[] getData = memoryStream.ToArray();//将内存流中的消息体写入字节数组int StartIndex = 0;//设置一个读取数据的起始下标while (true){if (receiveLength > 0)//如果接受到的消息不为0(不为空){int HeadLength = 0;//包头长度(包头+包体)if (getData.Length - StartIndex < 4)//包头接受不完整{HeadLength = -1;}else{//如果包头接受完整  转换成int类型的数值HeadLength = BitConverter.ToInt32(getData, StartIndex);}//包头接受完整但是消息体不完整              //包头接受不完整//↓↓↓↓↓↓↓↓                            ↓↓↓if (getData.Length - StartIndex < HeadLength || HeadLength == -1){memoryStream.Close();//关闭内存流memoryStream.Dispose();//释放内存资源memoryStream = new MemoryStream();//创建新的内存流memoryStream.Write(getData, StartIndex, getData.Length - StartIndex);//从新将接受的消息写入内存流break;}else{//如果消息(包头+包体)接受完整了,解析数据string str = Encoding.UTF8.GetString(getData, StartIndex + 4, HeadLength - 4);Console.WriteLine("接收到客户端的消息是-----" + str);StartIndex += HeadLength;//当读取一条完整的数据后,读取数据的起始下标应为当前接受到的消息体的长度(当前数据的尾部或下一条消息的首部)}}}}}
}

C#粘包和分包问题及解决方法相关推荐

  1. Linux下多进程服务端客户端模型二(粘包问题与一种解决方法)

    一.Linux发送网络消息的过程 (1) 应用程序调用write()将消息发送到内核中 ( 2)内核中的缓存达到了固定长度数据后,一般是SO_SNDBUF,将发送到TCP协议层 (3)IP层从TCP层 ...

  2. TCP粘包和拆包问题及其解决方法

    含义: TCP 传输协议是面向流的,没有数据包界限,也就是说消息无边界.客户端向服务端发送数据时,可能将一个完整的报文拆分成多个小报文进行发送,也可能将多个报文合并成一个大的报文进行发送.(TCP协议 ...

  3. 自定义Udp/Tcp协议,通信协议Socket/WebSocket,IM粘包、分包解决等(2),ProtocolBuffer

    > 自定义Udp/Tcp协议/通信协议(Java/C):自定义构建和解析IM协议消息:IM自定义UDP通信协议   类似于网络通信中的TCPIP协议一般,比较可靠的通信协议往往包含有以下几个组成 ...

  4. Netty解决TCP的粘包和分包(二)

    2019独角兽企业重金招聘Python工程师标准>>> Netty解决TCP的粘包和分包(二) 使用LengthFieldBasedFrameDecoder解码器分包 先看一下这个类 ...

  5. 粘包的原因分析及解决

    文章目录 1 粘包的原因分析 2 客户端解决粘包的问题 3 服务端解决粘包的问题 1 粘包的原因分析 先看一下数据收发的示意图: 我们之前每次只处理一帧数据,如果接收端的处理速度力和发送端的发送速度不 ...

  6. python串口数据分包_python TCP Socket的粘包和分包的处理详解

    概述 在进行TCP Socket开发时,都需要处理数据包粘包和分包的情况.本文详细讲解解决该问题的步骤.使用的语言是Python.实际上解决该问题很简单,在应用层下,定义一个协议:消息头部+消息长度+ ...

  7. socket的长连接、短连接、半包、粘包与分包

    socket的半包,粘包与分包的问题和处理代码:http://blog.csdn.net/qq_16112417/article/details/50392463 知乎关于长连接和短连接:https: ...

  8. socket的半包,粘包与分包的问题

    首先看两个概念:  短连接:   连接->传输数据->关闭连接     HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.     也可以这样 ...

  9. Python 下载依赖包环境经常失败超时解决方法

    Python 下载依赖包环境经常失败超时解决方法 参考文章: (1)Python 下载依赖包环境经常失败超时解决方法 (2)https://www.cnblogs.com/boonya/p/11909 ...

最新文章

  1. 浏览器--如何让登陆页面的表单不默认显示账号和密码
  2. android app系统的测试_计算机毕设项目003之基于Android系统的App点餐外送系统
  3. Eclipse jee 配置Tomcat5.5
  4. WinForm中 事件 委托 多线程的应用【以一个下载进度条为例】
  5. 第二十期:想吃透监控系统,就这一篇够不够?
  6. python 生成器函数_Python 生成器函数
  7. 垂直型电商的投资魔法
  8. 华为机试HJ1:字符串最后一个单词的长度
  9. 笔者认为,中国的互联网行业需要真正的CEO
  10. iOS ffmpeg + libfdk-aac
  11. AMOS问卷数据建模前传【SPSS 052期】
  12. 【乌拉喵.教程】TestBench仿真给输出脚赋值引起的问题
  13. C语言题目——三子棋游戏
  14. Linux 上的NetworkManager示例
  15. 邮政出面打假?中国邮政是否考虑搭建其品牌官网?
  16. 阿里云实践 - HTML5断点播放m3u8视频(videojs)
  17. 面试分享:专科半年经验面试阿里前端P6+总结
  18. 360查出 HEUR/Malware.QVMxx.Gen 病毒含义
  19. 通过server酱来发送爬虫爬到的数据
  20. 利用Python画一只小猪佩奇

热门文章

  1. 创建表的两种方式 [MySQL][数据库]
  2. python实时股票数据折线图_如何获取实时的股票数据?
  3. scratch如何让球随便移动
  4. 编写ActiveX控件及其打包方法
  5. Flink乱序延迟时间处理-Watermark
  6. 软件开发人员的三条职业路径
  7. CentOS下直播和点播服务搭建
  8. GBase项目管理实践总结——研发项目复盘简介
  9. linux命令cp命令行参数,linux cp(复制)命令参数详解
  10. 小型元器件介绍:色环电阻