有一个接收器在循环并调用socket.recv
:
import socket
import time
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet # UDP
sock.bind((UDP_IP, UDP_PORT))
sock.settimeout(0.001)
while True:
try:
data = sock.recv(1024) # buffer size is 1024 bytes
except socket.timeout:
pass
time.sleep(0.01)
发件人使用socket.sendto
循环发送消息,并递增计数:
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet # UDP
TOTAL_TO_SEND = 10000
messages = [str.encode(f"{num}") for num in range(TOTAL_TO_SEND)]
for total_sent in messages:
sock.sendto(total_sent, (UDP_IP, UDP_PORT))
使用此设置,在发送方发送下一条消息之前,接收方的循环速度不足以回到recv
行。
使用UDP允许丢失数据,我认为也许在接收者尚未回到recv
时到达的消息将被跳过。但是事实并非如此。
当我仅发送10,000条消息(TOTAL_TO_SEND = 10000
)时,即使发送几乎立即完成,接收方也需要花费一些时间来浏览所有10000条消息,但不会跳过任何一条。这意味着在接收者尚未准备好时,到达的消息会有一些缓冲/队列,它们会一直存储,直到接收者的代码能够处理所有消息为止。
但是,当我发送10倍的消息(TOTAL_TO_SEND = 100000
)时,会有一个截止值(对于我的最新运行为15355),在该截止值以下将处理每条消息,此后它一次跳过数百条。在我看来,这意味着缓冲区/队列已满,然后循环仅足够快,不足以处理每发送几百条消息中的一条消息。
有限大小队列理论的更多证据是,增加消息大小(通过在每个消息前添加一些0)可以降低开始跳过消息的截止时间。每个邮件前面加上100 0将导致截止时间为641,而不是15355。
我无法找到关于此行为的详尽解释,所以想知道这里是否有人知道此“数据包队列”在Python套接字中的工作方式以及它的参数是什么。它的大小已知吗?可以增加吗?消息消失之前有时间限制吗?有相关文件吗?
谢谢!
答案 0 :(得分:0)
这不完全是“详尽的解释”,而是一些信息:
您可以使用getsockopt和setsockopt在Python中查看和设置套接字的参数。
在这种情况下,相关参数是接收缓冲区的大小,即socket.SO_RCVBUF
。
print(sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF))
给我看了65536
。
您可以使用
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536 * 100)
使其比原来大100倍。这样的结果是在开始跳过消息之前,缓冲区中存储的数据量是原来的100倍。
将其设置得太大可能不是一个好主意,但是我不知道,所以我会让其他人对此感到高兴。