8

在两台主机之间的 udp 中使用非阻塞读取时,我遇到了丢失消息的问题。发件人在 linux 上,读者在 winxp 上。python中的这个例子显示了这个问题。
以下是用于显示问题的三个脚本。
发送.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))

读取.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 给出这个好的结果:

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?

4

2 回答 2

8

如果数据报到达主机(如您的wireshark日志所示),那么我首先要看的是您的套接字recv缓冲区的大小,使其尽可能大,并尽可能快地运行。

当然,这完全是 UDP 所期望的。你应该假设数据报可以在任何时候以任何理由被丢弃。此外,您可能会多次收到数据报...

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

于 2010-10-18T16:23:57.813 回答
8

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

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

我怀疑您是否溢出了 36030 字节的接收缓冲区,但是我从来没有在 Windows 上进行网络连接,因此您最好SO_RECVBUF按照@Len 的建议检查接收器上套接字选项的值。

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

于 2010-10-18T20:40:57.433 回答