【问题标题】:How to create IPv6 socket at python? Why got the socket.error: (22, 'Invalid argument')?如何在 python 中创建 IPv6 套接字?为什么得到 socket.error: (22, 'Invalid argument')?
【发布时间】:2011-04-17 15:11:23
【问题描述】:

我想在 python 上创建 Ipv6 套接字,我这样做:

#!/usr/bin/env python
import sys
import struct
import socket

host = 'fe80::225:b3ff:fe26:576'
sa = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sa.bind((host , 50000))

但是失败了:

socket.error: (22, 'Invalid argument') ?

谁能帮助我?谢谢!

我就这样重做了,还是不行

    >>>host = 'fe80::225:b3ff:fe26:576'
    >>>sa = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    >>>res = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)
    >>>family, socktype, proto, canonname, sockaddr = res[0]
    >>>print sockaddr
('fe80::225:b3ff:fe26:576', 50001, 0, 0)
    >>>sa.bind(sockaddr)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<string>", line 1, in bind
socket.error: (22, 'Invalid argument')

【问题讨论】:

  • 你确认socket.has_ipv6返回true了吗?
  • 为什么要绑定到任意链接本地地址?在 99% 的情况下,您希望绑定到 ::(即所有接口)。

标签: python sockets ipv6


【解决方案1】:

这个问题有两个部分

第一期

您应该使用 sa.bind(sockaddr),其中 sockaddr 是从 getaddrinfo 获得的

>>> HOST = 'localhost'
>>> PORT = 50007 
>>> res = socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)
>>> family, socktype, proto, canonname, sockaddr = res[1]
>>> proto
17
>>> sockaddr
('fe80::1%lo0', 50007, 0, 1)

第二期

如果您查看套接字文档中提供的示例

Socket 接受三个参数

socket( [family[, type[, proto]]])

根据文档

Create a new socket using the given address family, 
socket type and protocol number. The address family 
should be AF_INET (the default), AF_INET6 or AF_UNIX. 
The socket type should be SOCK_STREAM (the default), 
SOCK_DGRAM or perhaps one of the other "SOCK_" constants. 
The protocol number is usually zero and may be omitted in that case.

如果您使用 getaddressinfo 获取 proto 的值,则该值与默认值 0 不同

但是当我执行以下操作时,我得到了一个不同的协议值 - 17。 您可能也想对此进行调查。

当然 socket.has_ipv6 对我来说是正确的。

【讨论】:

  • 我已经用你的方法编辑了我的问题,其中包括 error.thanks >>> socket.has_ipv6 True
【解决方案2】:

上面缺少的另一件事是 fe80::* 是链接本地地址。因此,如果没有 Scope ID,您在技术上无法使用它们。
以防万一,“ link-local" 意味着地址只能用于特定链接,但推论是,由于地址是特定于链接的,理论上您可以在多个链接上使用相同的地址。
现在承认,在大多数情况下,链接本地地址是通过将已经唯一的硬件 (EUI-48) 地址转换为 EUI-64 然后翻转 U/L 来生成的位 (see) 但这不是生成链接本地地址的唯一方法,其他机制可能会导致重新使用该地址(我认为没有什么禁止这样做的)。所以现在你知道为什么它不起作用了。
下一个问题是如何修复它,或者更确切地说,您从哪里获得 Scope ID。 不幸的是,这并不明显。如果您阅读讨论“Scope”的 IPV6 RFC,您会发现它是以一般方式定义的。实际上,如果您在 Linux(可能还有 Windows/Mac?)中运行此代码,您可以使用接口索引。

请注意,目前 nss-mdns 中存在一个错误,即 .local 名称返回的范围 id 始终为零,因此在 Linux 中使用 .local 名称基本上不起作用,除非您的代码已经计算出范围 id 并设置它自己。

【讨论】:

    猜你喜欢
    • 2019-06-29
    • 1970-01-01
    • 2020-04-07
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多