在两个主机之间的udp中使用非阻塞读取时,我遇到了丢失消息的问题.发件人在linux上,读者在winxp上.python中的这个例子显示了这个问题.
以下是用于显示问题的三个脚本.
send.py:
import socket, sys s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) host = sys.argv[1] s.sendto('A'*10, (host,8888)) s.sendto('B'*9000, (host,8888)) s.sendto('C'*9000, (host,8888)) s.sendto('D'*10, (host,8888)) s.sendto('E'*9000, (host,8888)) s.sendto('F'*9000, (host,8888)) s.sendto('G'*10, (host,8888))
read.py
import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(('',8888)) while True: data,address = s.recvfrom(10000) print "recv:", data[0],"times",len(data)
read_nb.py
import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(('',8888)) s.setblocking(0) data ='' address = '' while True: try: data,address = s.recvfrom(10000) except socket.error: pass else: print "recv:", data[0],"times",len(data)
示例1(工作正常):
ubuntu> python send.py
winxp> read.py
从read.py得到这个ok结果:
recv:A次10次
recv:B次9000次
recv:C次9000次
recv:D次10次
recv:E次9000次
recv:F次9000次
recv:G次10次
示例2(缺少消息):
在这种情况下,read_nb.py通常不会捕获短消息.我给出了它的两个示例.
ubuntu> python send.py
winxp> read_nb.py
从read_nb.py给出这个结果:
recv:A次10次
recv:B次9000次
recv:C次9000次
recv:D次10次
recv:E次9000次
recv:F次9000次
上面是缺少的最后10个字节的消息
下面是中间丢失的10字节消息
recv:A次10次
recv:B次9000
recv:C次9000
recv:E次9000
recv:F次9000
recv:G次10
我已经在windows上检查过wireshark,并且每次捕获所有消息时它们都会到达主机接口,但不会被read_nb.py捕获.解释是什么?
我也尝试过使用linux上的read_nb.py和windows上的send.py,然后就可以了.所以我认为这个问题与winsock2有关
或者我可能以错误的方式使用非阻塞udp?
如果数据报到达主机(正如你的wireshark日志所示),那么我看到的第一个地方是套接字recv缓冲区的大小,尽可能大,并尽可能快地运行.
当然,这完全是UDP的预期.您应该假设数据报可以随时因任何原因丢弃.您也可以多次获得数据报...
如果您需要可靠性,那么您需要构建自己的,或使用TCP.
使用UDP丢失消息是正常的 - 传输层不保证数据报的顺序或传递.如果您希望它们按顺序和/或始终交付,请自行切换到TCP或实施排序和/或确认/超时/重传.
对于您的示例 - 大消息大于普通以太网MTU 1500减去八个字节的UDP报头(除非您使用巨型帧),因此将由发送方分段.这会给发送器和接收器带来更多负载,但接收器上的负载更多,因为它需要将片段保留在内核内存中,直到完整的数据报到达为止.
我怀疑你是否溢出了36030字节的接收缓冲区,但后来我从不在Windows上进行网络连接,所以你最好检查SO_RECVBUF
接收器上套接字选项的值,如@Len建议的那样.
还要检查输出netstat -s
以查看丢弃的数据包计数.