确保通过 Python 中的 UDP 套接字接收所有数据

Posted

技术标签:

【中文标题】确保通过 Python 中的 UDP 套接字接收所有数据【英文标题】:Ensuring all the data gets received through UDP socket in Python 【发布时间】:2014-10-12 00:41:36 【问题描述】:

可能相关的问题似乎很接近,但并未按照我的理解描述我的问题:

Reading all the data from a UDP socket Python UDP socket semi-randomly failing to receive Python raw socket listening for UDP packets; only half of the packets received

问题

逐行发送的长文件不会一直通过 UDP over loopback。

长篇大论

我有一个由行和中断组成的长文件,这与我通过本地 UDP 从另一个程序获得的内容相同。让我强调一下,发送数据包的程序将通过 UDP 进行(这里没有选择),并且在发送时无法修改以处理 ACK 请求等。

看起来像这样(这是尾巴):

StimulusTime 56398

Signal(0,2) -79.5457

Signal(0,4) -81.7426

Signal(0,6) -83.9978

Signal(0,9) -63.3755

Signal(0,11) -15.6045

Signal(0,13) 31.1299

Signal(0,16) 75.7539

Signal(0,18) 98.301

Signal(0,20) 98.301

Signal(0,22) 48.4546

Signal(0,25) 3.73159

Signal(0,27) -49.9798

Signal(0,29) -77.8449

Signal(1,0) -22.0332

Signal(1,2) -60.6384

Signal(1,4) -98.0858

Signal(1,6) -86.4579

Signal(1,9) -68.9173

Signal(1,11) -31.5552

Signal(1,13) 35.2906

Signal(1,16) 77.0686

Signal(1,18) 96.3836

Signal(1,20) 95.7246

Signal(1,23) 25.6074

Signal(1,25) -20.2101

Signal(1,27) -60.2933

Signal(1,29) -83.8169

Signal(2,0) -31.8826

Signal(2,2) -53.5045

Signal(2,4) -89.9895

Signal(2,7) -84.4503

Signal(2,9) -59.7016

Signal(2,11) -12.8569

Signal(2,13) 28.857

Signal(2,15) 58.0577

Signal(2,18) 96.4222

Signal(2,20) 79.783

Signal(2,22) 58.6463

Signal(2,25) -3.24883

Signal(2,27) -45.5

Signal(2,29) -88.8937

Signal(3,0) -18.6625

Signal(3,2) -53.3978

Signal(1,16) 58.784

Signal(1,17) 44.7782

Signal(1,18) 6.247

Signal(1,19) -12.0855

Signal(1,20) -33.7644

Signal(1,21) -49.4406

Signal(1,22) -67.5791

Signal(1,23) -92.0336

Signal(1,24) -93.9841

END

我编写了获取该文件的代码,并在本地通过 UDP 一次发送一行,然后代码接收它并根据数据类型对其进行解析。

发件人:

import socket
import sys

# Sends udp test data piped in from STDIN to the listener.
# ex: cat sampleoutput.txt | python testsender.py 

UDP_IP = "127.0.0.1"
UDP_PORT = 5000

print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT

sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_DGRAM) # UDP

# Send from stdin
if len(sys.argv) < 2:
  while True:
    line = sys.stdin.readline()
    if line:
      sock.sendto(line, (UDP_IP, UDP_PORT))
    else:
      break

  # get from file arg
else:
  myfile = open(str(sys.argv[1]), "r")
  while True:
    line = myfile.readline()
    if line:
      sock.sendto(line, (UDP_IP, UDP_PORT))
    else:
      break


sock.close()

听众:

import socket
from array import array

UDP_IP = "127.0.0.1"
UDP_PORT = 5000

sock = socket.socket(socket.AF_INET,  # Internet
                     socket.SOCK_DGRAM)  # UDP
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)  # buffer size arg

    print data
    # write to file for later testing
    # file = open("testdummy.txt", "a")
    # file.write(data)
    if data == "END\n":
        break

我能够使用上面的监听器从原始程序生成测试文件,所以它应该可以工作。不幸的是,根据tail -n 500 testdummy.txt | python testsender.py 的测试,它在大约 500 行有效载荷中失败,尽管它有些随机。具体来说,侦听器在发送者退出之前没有收到所有发送的行,让它挂起,等待"END\n" 字符串。

据我了解,套接字已经处于阻塞模式——如何防止这种情况发生?

【问题讨论】:

UDP 不可靠,它不保证所有数据都会通过。如果发送太快,内核缓冲区会填满并开始丢弃它们。 如果你不想使用TCP,它保证了顺序传输,你必须实现自己的逻辑来检测丢失的数据包并重新发送它们。这就是为什么 UDP 很少用于批量传输的原因。 另见***.com/questions/3034680/…。 【参考方案1】:

我给您的第一个建议是,如果您想传输保留行序列的文件,请不要使用 UDP,如果您不想编写大量代码,请使用 TCP。原因是;

    UDP 是一个不可靠的协议,从某种意义上说,发送的数据包不能保证被接收者接收。 UDP 不保证接收数据包的顺序,这是因为 UDP 数据包可能通过多个路由(计算机之间的跃点)到达接收方。所以后面发送的数据包可以在前面发送的数据包之前走一条短途并到达接收者。 (“End\n”数据包可以在其他数据包之前)

另一方面,TCP 是可靠的,并且可以保证接收到的数据包的顺序。文件传输的理想选择。

但不用担心文件共享应用程序,如 Bear Share、Bit Torrents 使用 UDP,但您还需要进行一些额外的编码。

    您需要实现一个确认协议,因为您需要为发送给接收者的每个数据包提供一个唯一的 ID,并且当接收到数据包时,接收者应该将一个确认数据包发送回发送者,该 ID 表示数据包已收到。 如果数据包丢失并且没有到达收件人(收件人没有确认),您必须再次(并再次)重新发送数据包,直到收到确认。 您可以通过在收到前一个数据包的确认之前不发送下一个数据包来控制顺序。

【讨论】:

这是一个内容丰富的答案,但没有诊断出我的问题。 您使用了 UDP。 UDP不可靠。因此,一些数据包丢失。对我来说,这似乎是一种诊断。 “医生,我这样做会很痛!” “好吧,不要那样做!” 在我链接到的所有相关问题上重复已接受的教条不会对这个问题或整个网站做出贡献。这个答案非常笼统,非常适合维基教科书。在撰写本文时,关于这个问题的最具建设性的帖子是 @barmar 的帖子,它对我的​​具体问题有一些有用的信息(内核缓冲区等)。

以上是关于确保通过 Python 中的 UDP 套接字接收所有数据的主要内容,如果未能解决你的问题,请参考以下文章

Python中的UDP套接字:如何清除缓冲区并忽略oldes消息

C中的两种方式UDP套接字

Python Raw Socket 无法接收 ICMP 消息;出现在 Wireshark 中

udp为啥收不到广播中的数据,该怎么处理

通用 Windows 上的 UDP 套接字未接收数据

python中的TCP及UDP