如何在Python(Python 2)中找到UDP有效负载的最大长度,最好是与平台无关?
具体来说,我想避免[Errno 90] Message too long
AKA errno.EMSGSIZE
。
IPv4数据包格式seems to be 65507允许的最大值。
要查看错误:
import socket
msg_len = 65537 # Not even possible!
ip_address = "127.0.0.1"
port = 5005
msg = "A" * msg_len
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(msg, (ip_address, port))
答案 0 :(得分:3)
您的部分场所需要进行小幅修正。
由于IP头包含16位字段的长度,IPv4消息的最大大小可以是65535
字节,并且包括IP头本身。
IP数据包本身至少有一个20字节的标头。因此,65535 - 20 == 65515
是IP消息的有效负载的最大大小。有效载荷可以是UDP数据报。
UDP数据报本身通常是一个8字节的标头。因此65515 - 8 == 65507
。因此,即使UDP报头理论上在其自己的长度字段中包含的数量高于65507,IPv4消息也不能包含它。
但是如果你的系统向IP头添加了更多的头(通过socket ioctls或其他任何选项字段),那么UDP应用程序有效负载的限制将减少相应的数量。
实际上,任何高于网络适配器MTU大小的IP消息(~1500字节)都会触发UDP数据包进行IP分片。因此,如果您的以太网卡具有1500字节的消息大小,则包含65507字节应用程序数据的UDP数据报将被分段为大约43个独立的以太网帧。每个帧都是一个分段的IP数据包,包含UDP字节的子集,但具有单独的标头。当在远程端接收到所有IP片段时,它在逻辑上以65507字节数据报的形式传送到应用程序。碎片对应用程序是透明的。
我建议使用Wireshark运行您的代码并发送到网络外的真实IP地址。您可以观察和研究IP碎片的工作原理。
答案 1 :(得分:1)
嗯,总是有尝试和看到的方法......我不会称之为优雅,但它与平台无关:
import socket
def canSendUDPPacketOfSize(sock, packetSize):
ip_address = "127.0.0.1"
port = 5005
try:
msg = "A" * packetSize
if (sock.sendto(msg, (ip_address, port)) == len(msg)):
return True
except:
pass
return False
def get_max_udp_packet_size_aux(sock, largestKnownGoodSize, smallestKnownBadSize):
if ((largestKnownGoodSize+1) == smallestKnownBadSize):
return largestKnownGoodSize
else:
newMidSize = int((largestKnownGoodSize+smallestKnownBadSize)/2)
if (canSendUDPPacketOfSize(sock, newMidSize)):
return get_max_udp_packet_size_aux(sock, newMidSize, smallestKnownBadSize)
else:
return get_max_udp_packet_size_aux(sock, largestKnownGoodSize, newMidSize)
def get_max_udp_packet_size():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ret = get_max_udp_packet_size_aux(sock, 0, 65508)
sock.close()
return ret
print "Maximum UDP packet send size is", get_max_udp_packet_size()