« 上一篇下一篇 »

什么情况下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数值时(单播或组播报文),同时进行其它有延时的操作(如写码流数值到USB存储设备), 应该程序将延迟接收UDP数值包,而socket默认接收缓冲数据只有108544Byte,这样可能会使socket接收缓冲数据满,无法接收新的UDP数值包,出现丢包现象。

可在内核下通过执行下面指令进行确认:

cat /proc/net/snmp| grep Udp

如果RcvbufErrors字段增加较多,说明确实是socket接收缓冲数据满导致的丢包。

以下指令可以增加接收缓冲区,解决以上问题。

echo 20000000 >/proc/sys/net/core/rmem_max

echo 20000000 >/proc/sys/net/core/rmem_default

echo 20000000 >/proc/sys/net/core/netdev_max_backlog

这种改动,需要根据实际码流发送速度和接收程序的延时进行参数调优。

[cpp] view plain copy
/proc/sys/net/core/rmem_default   
/proc/sys/net/core/rmem_max   

   
使用udp接收数值时:   
若没有调用setsockopt设置系统接收缓冲数据,则接收缓冲数据的大小为rmem_default.   
若程序调用setsockopt设置系统接收缓冲数据,设置值不能超过rmem_max.   
   
系统会为每个udp socket申请一份缓冲数据空间,而不是共用同一份缓冲数据.   
即每个udp socket都会有一个rmem_default大小的缓冲数据空间(假设没有setsockopt设置).