使用非阻塞 udp 读取时丢失消息
在两台主机之间使用 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 给出这个好的结果:
recv: A times 10
接收:B 乘以 9000
接收:C 乘以 9000
接收:D 乘以 10
接收:E 次 9000
接收:F 乘以 9000
recv:G 乘以 10
示例 2(丢失消息):
在这种情况下,短消息通常不会被 read_nb.py 捕获 我举两个例子来说明它的样子。
ubuntu> python send.py
winxp> read_nb.py
从 read_nb.py 给出此结果:
recv:A 乘以 10
接收:B 乘以 9000
接收:C 乘以 9000
接收:D 乘以 10
接收:E 次 9000
recv: F 乘以 9000
上面是最后一个 10 字节消息丢失
下面是中间丢失的 10 字节消息
recv: A 乘以 10
接收:B 乘以 9000
接收:C 乘以 9000
接收:E 次 9000
接收:F 乘以 9000
recv:G乘10
我已经在Windows上使用wireshark进行了检查,每次捕获所有消息时,它们都会到达主机接口,但不会被read_nb.py捕获。解释是什么?
我还尝试过在 Linux 上使用 read_nb.py 和在 Windows 上使用 send.py,然后它就可以工作了。 所以我认为这个问题与winsock2有关
或者我可能以错误的方式使用非阻塞udp?
I have problem with missing messages when using nonblocking read in udp between two hosts. The sender is on linux and the reader is on winxp. This example in python shows the problem.
Here are three scripts used to show the problem.
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)
Example 1 (works ok):
ubuntu> python send.py
winxp > read.py
give this ok result from read.py:
recv: A times 10
recv: B times 9000
recv: C times 9000
recv: D times 10
recv: E times 9000
recv: F times 9000
recv: G times 10
Example 2 (missing messages):
in this case the short messages will often not be catched by read_nb.py
I give two examples of how it can look like.
ubuntu> python send.py
winxp > read_nb.py
give this result from read_nb.py:
recv: A times 10
recv: B times 9000
recv: C times 9000
recv: D times 10
recv: E times 9000
recv: F times 9000
above is the last 10 byte message missing
below is a 10 byte message in the middle missing
recv: A times 10
recv: B times 9000
recv: C times 9000
recv: E times 9000
recv: F times 9000
recv: G times 10
I have checked with wireshark on windows and every time all messages is captured so they reach the host interface but is not captured by read_nb.py. What is the explanation?
I have also tried with read_nb.py on linux and send.py on windows and then it works.
So I figure that this problem has something to do with winsock2
Or maybe I am using nonblocking udp the wrong way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对于 UDP,丢失消息是正常现象 - 传输层不保证数据报的顺序或传送。如果您希望它们按顺序和/或始终交付,请切换到 TCP 或自行实现排序和/或确认/超时/重传。
对于您的示例 - 大消息大于 1500 的正常以太网 MTU 减去 UDP 标头的 8 个字节(除非您使用巨型帧),因此将被发送者分段。这会给发送方和接收方带来更多的负载,但也会给接收方带来更多的负载,因为它需要将碎片保留在内核内存中,直到完整的数据报到达。
我怀疑你的接收缓冲区溢出了 36030 字节,但我从来没有在 Windows 上进行网络连接,所以你最好按照 @Len 的建议检查接收器上的
SO_RECVBUF
套接字选项的值。另请检查 的输出
netstat -s
查看丢弃的数据包计数。Losing messages is normal with UDP - the transport layer does not guarantee order or delivery of datagrams. If you want them in order and/or always delivered, switch to TCP or implement sequencing and/or ack/timeout/retransmission yourself.
To your example - the large messages are larger then normal ethernet MTU of 1500 minus eight bytes of UDP header (unless you are using jumbo frames) and thus will be fragmented by the sender. This puts more load onto both sender and receiver, but more on the receiver since it needs to keep fragments in kernel memory until the full datagram arrives.
I doubt you are overflowing the receive buffer with 36030 bytes, but then I never do networking on Windows, so you better check the value of
SO_RECVBUF
socket option on the receiver as @Len suggests.Also check the output of
netstat -s
to see the dropped packet counts.如果数据报到达主机(如您的wireshark日志所示),那么我首先要查看的是套接字接收缓冲区的大小,使其尽可能大,并尽可能快地运行。
当然,这完全是 UDP 所期望的。您应该假设数据报可以在任何时候、出于任何原因被丢弃。此外,您可能会多次获得数据报...
如果您需要可靠性,那么您需要构建自己的数据报,或使用 TCP。
If the datagrams are getting to the host (as your wireshark log shows) then the first place I'd look is the size of your socket recv buffer, make it as big as you can, and run as fast as you can.
Of course this is completely expected with UDP. You should assume that datagrams can be thrown away at any point and for any reason. Also you may get datagrams more than once...
If you need reliability then you need to build your own, or use TCP.