查找最大UDP负载--python套接字发送/发送到
如何在Python(Python 2)中找到UDP有效负载的最大长度,最好是独立于平台的 具体来说,我希望避免查找最大UDP负载--python套接字发送/发送到,python,sockets,networking,udp,Python,Sockets,Networking,Udp,如何在Python(Python 2)中找到UDP有效负载的最大长度,最好是独立于平台的 具体来说,我希望避免[Errno 90]消息太长AKAErrno.EMSGSIZE 背景 UDP数据包格式允许的最大值) IPv4数据包格式允许的最大值 但似乎是这样 我不是在问什么 ? 一个IPv4数据报可以容纳的最大UDP负载是多少 一个以太网帧可以容纳的最大UDP负载是多少 演示代码 要查看操作中的错误,请执行以下操作: import socket msg_len = 65537 # No
[Errno 90]消息太长
AKAErrno.EMSGSIZE
背景
- UDP数据包格式允许的最大值)
- IPv4数据包格式允许的最大值
- 但似乎是这样
- ?
- 一个IPv4数据报可以容纳的最大UDP负载是多少
- 一个以太网帧可以容纳的最大UDP负载是多少
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))
嗯,总有一种“试一试”的方法。。。我不认为这很优雅,但它是平台独立的:
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()
嗯,总有一种“试一试”的方法。。。我不认为这很优雅,但它是平台独立的:
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()
你的一些前提需要一个小的修正 由于IP报头包含一个16位的长度字段,IPv4消息的最大大小可以是
65535
字节,其中包括IP报头本身
IP数据包本身至少有一个20字节的报头。因此,65535-20=65515
是IP消息的有效负载的最大大小。有效负载可以是UDP数据报
UDP数据报本身通常是一个8字节的报头。因此65515-8==65507
。因此,即使理论上UDP报头在其自身的长度字段中包含的数量高于65507,IPv4消息也不能包含它
但是,如果您的系统向IP报头添加更多报头(通过套接字ioctls或其他方式添加选项字段),则UDP应用程序负载的限制将相应减少
实际上,任何超过网络适配器MTU大小(约1500字节)的IP消息都会触发UDP数据包进行IP分段。因此,如果您的以太网卡的消息大小为1500字节,则包含65507字节应用程序数据的UDP数据报将分为大约43个单独的以太网帧。每个帧都是一个片段化的IP数据包,包含UDP字节的子集,但有一个单独的报头。当远程端接收到所有IP片段时,它在逻辑上作为65507字节的数据报传递给应用程序。碎片对应用程序是透明的
我建议您使用Wireshark运行代码,并将其发送到网络外的真实IP地址。您可以观察和研究IP碎片是如何工作的。您的一些前提需要进行轻微的更正 由于IP报头包含一个16位的长度字段,IPv4消息的最大大小可以是
65535
字节,其中包括IP报头本身
IP数据包本身至少有一个20字节的报头。因此,65535-20=65515
是IP消息的有效负载的最大大小。有效负载可以是UDP数据报
UDP数据报本身通常是一个8字节的报头。因此65515-8==65507
。因此,即使理论上UDP报头在其自身的长度字段中包含的数量高于65507,IPv4消息也不能包含它
但是,如果您的系统向IP报头添加更多报头(通过套接字ioctls或其他方式添加选项字段),则UDP应用程序负载的限制将相应减少
实际上,任何超过网络适配器MTU大小(约1500字节)的IP消息都会触发UDP数据包进行IP分段。因此,如果您的以太网卡的消息大小为1500字节,则包含65507字节应用程序数据的UDP数据报将分为大约43个单独的以太网帧。每个帧都是一个片段化的IP数据包,包含UDP字节的子集,但有一个单独的报头。当远程端接收到所有IP片段时,它在逻辑上作为65507字节的数据报传递给应用程序。碎片对应用程序是透明的
我建议您使用Wireshark运行代码,并将其发送到网络外的真实IP地址。你可以观察和研究IP碎片是如何工作的。相关:我认为没有一种便携的方式来获取这些信息。这不是socket API的一个特性。相关:我认为没有一种可移植的方式来获取这些信息。这不是socket API的一个特性。“碎片对应用程序是透明的。”这是真的,但碎片和重新组装需要时间。此外,许多路由器和大多数防火墙只允许第一个碎片通过,因为碎片用于攻击。如果整体的任何一个片段丢失,则整个将被丢弃。碎片真的不再实用了。Ron,我正要写一些关于IP碎片可靠性问题的类似细节,以及为什么在UDP字段中重载太多数据不是一个好主意。现代路由器会限制碎片的数量是可以理解的,但如果它将碎片数量限制为1,我会非常惊讶。(但是,嘿,我每天都学到一些新东西。)我更多的是写关于目标路由器或防火墙的文章。默认情况下,大多数防火墙不再允许碎片。企业通常在路由器上配置相同的东西。我总是很惊讶,人们希望用尽可能多的数据加载不可靠的协议,知道丢失一个数据包会丢失更多的数据。谢谢Ron。事实上,我很好奇要测试这个,因为我坚持。但是我还没有实现对的PADDING属性支持,因为我从来没有看到它的必要性(以及一些公共服务器的安全问题)。测试我所使用的各种网络会很有趣。“碎片对应用程序是透明的。”这是真的,但碎片和重组需要时间。而且,许多路由器和大多数防火墙只允许第一个片段通过,因为fragmen