美文网首页
丢包?粘包?为什么?怎么办

丢包?粘包?为什么?怎么办

作者: 一枚64byte的仙女 | 来源:发表于2021-02-24 14:14 被阅读0次

tcp粘包和upd丢包

先说粘包的原因:

1.要发送的数据小于TCP发送缓存区的大小,TCP将多次写入缓冲区的数据一次全部发送出去,则会出现粘包

2.接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包

拆包的原因

1.要发送的数据大于TCP发送缓冲区的剩余大小,(一般大小为16k,也可以通过自己通过setsockopt()设置)

2.待发送的数据大于MSS(最大报文长度MSS=MTU-20字节TCP报头-20字节IP报头)

粘包拆包

1.消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格,发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来

2.在包尾增加回车换行符进行分割,例如FTP协议

3.可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

4.将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路是消息头的第一个字段用int来表示消息的总长度。发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了

5.更复杂的应用层协议

建议TCP使用写入的流是按 长度 + 内容 + 长度 + 内容 ,这样就可以非常简单的解决粘包问题

最好不要采用所谓的 开始标识 + 数据 + 结束标识 来分包, 适用性极低, 错误率极高, 除非数据都是固定有格式, 否则不要采用这种方式

UDP传送当中, 只存在丢包的可能, 收到包的时候, 肯定这个包的内容就是正确的, 极少会有错误的

UDP 丢包

1、接收端处理时间过长导致丢包:调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续recv。

2、发送的包巨大丢包:虽然send方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过50K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。

3、发送的包较大,超过接受者缓存导致丢包:包超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题,我把接收缓冲设置成64K就解决了。

int nRecvBuf=32*1024;//设置为32K

setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

4、发送的包频率太快:虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。所以在发送频率过快的时候还是考虑sleep一下吧。

5、局域网内不丢包,公网上丢包。这个问题我也是通过切割小包并sleep发送解决的。如果流量太大,这个办法也不灵了。总之udp丢包总是会有的,如果出现了用我的方法解决不了,还有这个几个方法: 要么减小流量,要么换tcp协议传输,要么做丢包重传的工作。

丢包常见的原因

一个是客户端发送过快,网络状况不好或者超过服务器接收速度,就会丢包。

第二个原因是服务器收到包后,还要进行一些处理,而这段时间客户端发送的包没有去收,造成丢包。

那么需要做的是

客户端降低发送速度,可以等待回包,或者加一些延迟。服务器部分单独开一个线程,去接收UDP数据,存放在一个缓冲区中,又另外的线程去处理收到的数据,尽量减少因为处理数据延时造成的丢包。

有两种方法解决UDP 丢包的问题:

方法一:重新设计一下协议,增加接收确认超时重发。(推荐)

方法二:在接收方,将通信和处理分开,增加个应用缓冲区;如果有需要增加接收socket的系统缓冲区。(本方法不能从根本解决问题,只能改善)

相关文章

网友评论

      本文标题:丢包?粘包?为什么?怎么办

      本文链接:https://www.haomeiwen.com/subject/mhfsfltx.html