在两台主机之间的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?
答案 0 :(得分:7)
如果数据报到达主机(正如你的wireshark日志所示),那么我看到的第一个地方就是套接字recv缓冲区的大小,尽可能大,并尽可能快地运行
当然,UDP完全可以预期。您应该假设数据报可以随时因任何原因丢弃。您也可以多次获得数据报......
如果您需要可靠性,那么您需要构建自己的,或使用TCP。
答案 1 :(得分:5)
使用UDP丢失消息是正常的 - 传输层不保证数据报的顺序或传送。如果您希望它们按顺序和/或始终交付,请自行切换到TCP或实施排序和/或确认/超时/重传。
对于您的示例 - 大型消息大于正常的以太网MTU 1500减去八个字节的UDP标头(除非您使用巨型帧),因此将被发送方分段。这会给发送器和接收器带来更多负载,但接收器上的负载会更多,因为它需要将片段保留在内核内存中,直到完整的数据报到达为止。
我怀疑你是否正在以36030字节溢出接收缓冲区,但后来我从不在Windows上进行网络连接,因此你最好检查接收器上SO_RECVBUF
套接字选项的值,如@Len所示。
同时检查netstat -s
的输出以查看丢弃的数据包计数。