精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
通信粘包是指接收时收到了发送端多次混合起来的数据包,理想状态是一发一收,发送端和接收端都好处理,但是实际上理想状态总是有偏差的。在大并发操作系统通信负荷大、模拟环境虚拟机性能差、进程线程多进程通信负荷大和网络节点通信压力大,偏差波动越来越大,就会产生粘包。
串口通信开发比SOCKET套接字简单,但是里面也有时序参数配置,配置不好通信也容易异常。在使用虚拟串口软件或虚拟机VMWare操作系统通信时,有偏差极端情况 下会有串口粘包。在串口开发时,特别相信会是一发一收理想状态,但是我就在偏差极端情况下遇到过串口粘包。一组一组数据取出来,发现不适合用,加上包头包尾标志判断才算处理好。
SOCKET粘包和TCP粘包经常放到一起来讲,因为TCP的缓冲机制,容易让小包聚集在接收端,或者大包上个的后半部分和下包的上半部分聚集在一起,网上的文章说解决办法有:短连接、固定长度、分隔符和专门的Length字段,其实这些处理不办法不全面,最好是长度和包标志都带上,类似TCP底层的包结构。另外在具体编程时,注意用强制刷新缓冲区让操作系统不等待,立即发送来进行控制。
锐英源软件从事过OpenSSL通信开发,用到过刷新缓冲区,代码如下:
iwrite = SSL_write(ssl, psend, ilen); BIO_flush(sbio); if (iwrite <= 0) { strcpy(szErrMsg, "发送命令失败"); LOG_ERROR << cUser << "配置中断----发送命令失败"; //LogSSLError(("写")); bCommError = true; return iwrite; }
BIO_flush就是强制刷新缓冲区函数。
把长度和包标志都带上后,接收端接收时按流式缓冲处理,先接收长度,再按长度接收数据,判断尾部正确与否,不正确抛弃,同时回复给发送端错误信息;正确就处理,并从头删掉开头长度的缓冲数据。
C++一般用原生函数send和recv处理,不太好实现流式缓冲处理,不过网上有源代码封装的不错,大家可以找找。C#的NetworkStream和MemoryStream类似类比较多,处理方便。如果初学者不太好用C++掌握,用C#开发相应的处理代码,容易掌握流的原理。锐英源软件用C#开发过教育平台,平台里有组播和点对点通信,通信状态很复杂,但是用好了C#流处理,处理好了SOCKET粘包和TCP粘包问题。
如果大家想证实粘包情况,可以用wireshark抓包,如果操作系统卡,觉得wireshark不方便打开,用tshark来抓包也行,在卡的时候,迟迟收不到发送端的数据包,在突然收到时就会是粘包情况。
粘包不复杂,但是最好不要让出现粘包,开始就设计好服务器端和客户端架构,保证通信吞吐能力,不让数据处理出现波动,才是更好的解决方案。