使用非阻塞udp读取时缺少消息

时间:2010-10-18 15:28:07

标签: python sockets udp nonblocking winsock2

在两台主机之间的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?

2 个答案:

答案 0 :(得分:7)

如果数据报到达主机(正如你的wireshark日志所示),那么我看到的第一个地方就是套接字recv缓冲区的大小,尽可能大,并尽可能快地运行

当然,UDP完全可以预期。您应该假设数据报可以随时因任何原因丢弃。您也可以多次获得数据报......

如果您需要可靠性,那么您需要构建自己的,或使用TCP。

答案 1 :(得分:5)

使用UDP丢失消息是正常的 - 传输层不保证数据报的顺序或传送。如果您希望它们按顺序和/或始终交付,请自行切换到TCP或实施排序和/或确认/超时/重传。

对于您的示例 - 大型消息大于正常的以太网MTU 1500减去八个字节的UDP标头(除非您使用巨型帧),因此将被发送方分段。这会给发送器和接收器带来更多负载,但接收器上的负载会更多,因为它需要将片段保留在内核内存中,直到完整的数据报到达为止。

我怀疑你是否正在以36030字节溢出接收缓冲区,但后来我从不在Windows上进行网络连接,因此你最好检查接收器上SO_RECVBUF套接字选项的值,如@Len所示。

同时检查netstat -s的输出以查看丢弃的数据包计数。