如何在python中设置套接字选项IP_DONTFRAG?



如何使用python套接字在IP标头中设置DONT_FRAGMENT标志?

以下代码

socket.setsockopt(socket.IPPROTO_IP, socket.IP_DONTFRAG, 1)

给我这个错误:

AttributeError: 'module' object has no attribute 'IP_DONTFRAG'

有人有想法吗?

<小时 />
def create_sender_session(self):
logging.debug("Create Sender Session")
if (self.send_ip_ver == 6 or self.resp_ip_ver == 6):
self.sender_socket = socket.socket(
socket.AF_INET6, socket.SOCK_DGRAM)
self.sender_socket.setsockopt(
socket.IPPROTO_IPV6, socket.IPV6_TCLASS, self.tos)
self.sender_socket.setsockopt(
socket.IPPROTO_IPV6, socket.IPV6_UNICAST_HOPS, self.ttl)
else:
self.sender_socket = socket.socket(
socket.AF_INET, socket.SOCK_DGRAM)
self.sender_socket.setsockopt(
socket.SOL_IP, socket.IP_TTL, self.ttl)
self.sender_socket.setsockopt(
socket.IPPROTO_IP, socket.IP_TOS, self.tos)
self.sender_socket.setsockopt(
socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sender_socket.bind((self.send_addr, self.send_port))
logging.info('Sender started: {}:{}'.format(
self.send_addr, self.send_port))

查找某些套接字选项的文档比其他套接字选项更难。*DONTFRAG似乎属于后一类。
一些参考资料:

  • [IBM]: setsockopt() - 设置 Socket Options

  • [FreeBSD]: IP(4) (重点是我的):

    IP_DONTFRAG可用于在 IP 数据包上设置"不分段"标志。目前这个选项只在 udp(4) 和原始 ip(4) 套接字上被使用, 除非已经设置了IP_HDRINCL选项。在 tcp(4) 套接字上, 不分段标志由路径 MTU 发现选项控制。发送大于出口接口的 MTU 大小(由目标地址确定)的数据包将返回 EMSGSIZE 错误。

(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q049051558]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[064bit prompt]> uname -a
Linux cfati-5510-0 5.10.60.1-microsoft-standard-WSL2 #1 SMP Wed Aug 25 23:20:18 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[064bit prompt]> head -n 2 /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
[064bit prompt]>
[064bit prompt]> python2 -c "import socket;print([e for e in dir(socket) if "DONTFRAG" in e])"
['IPV6_DONTFRAG']

需要注意的是,Python2不再维护(EndOfLife),尽管在提出问题时,它仍然是,因此将切换到Python3

[064bit prompt]> python -c "import socket;print([e for e in dir(socket) if "DONTFRAG" in e])"
['IPV6_DONTFRAG']

[Python.Docs]:socket - 低级网络接口没有提到它们。但是,似乎只有IPV6_DONTFRAG存在。
这并不是Python特有的。

[064bit prompt]> python -c "import socket, sys;print("{:s}n{:s}n{:d}n".format(sys.version, sys.platform, socket.IPV6_DONTFRAG))"
3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0]
linux
62
[064bit prompt]> grep -r DONTFRAG /usr/include
/usr/include/linux/in6.h:#define IPV6_DONTFRAG          62
/usr/include/x86_64-linux-gnu/bits/in.h:#define IPV6_DONTFRAG           62

正如IPV6_DONTFRAG名称所述,它特定于IPv6套接字(并且很可能不适用于IPv4):

[064bit prompt]> python
Python 3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import socket
>>>
>>> s6d = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
>>> s6d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
0
>>> s6d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
>>> s6d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
1
>>> s6d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 2)
>>> s6d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
1
>>> s6d.close()
>>>
>>> s6s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
>>> s6s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
>>> s6s.close()
>>>
>>> s4d = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 95] Operation not supported
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available
>>>
>>> s4d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available
>>> s4d.setsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available
>>> s4d.close()

因此,对于IPv6套接字,它没有引发异常(需要测试来确定它是否在引擎盖下做了应该做的事情)。
对于IPv4,可以尝试路径MTU发现选项([SO]:使用套接字选项的路径MTU发现- IP_MTU和IP_MTU_DISCOVER)。

不知道它有多相关,但它似乎正在为Win

[cfati@CFATI-5510-0:e:WorkDevStackOverflowq049051558]> "e:WorkDevVEnvspy_pc064_03.09_test0Scriptspython.exe"
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import socket
>>>
>>> s4d = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(0, 0)
>>> s4d.setsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG, 1)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(1, 1)
>>> s4d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(1, 1)
>>> s4d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 0)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(0, 0)
>>> s4d.close()
>>>
>>> s4s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s4s.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4s.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(1, 1)
>>> s4s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 0)
>>> s4s.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4s.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(0, 0)
>>> s4s.close()

最新更新