¿Cómo crear un socket IPv6 en Python? ¿Por qué obtuve el socket.error: (22, ‘Argumento no válido’)?

Quiero cear el socket de Ipv6 en python, lo hago así:

#!/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)) 

Pero falló:

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

¿Alguien puede ayudarme? ¡Gracias!

Lo rehago así, pero todavía no puedo trabajar.

  >>>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 "", line 1, in ? File "", line 1, in bind socket.error: (22, 'Invalid argument') 

Hay dos partes en el problema

Primer problema

Debe usar sa.bind (sockaddr) donde sockaddr se obtiene de 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) 

Segundo problema

Si observa el ejemplo provisto en la documentación de socket en

Socket acepta tres argumentos

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

Según la documentación

 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. 

Y si usó getaddressinfo para obtener los valores de proto, entonces el valor es diferente del valor predeterminado 0

Pero cuando ejecuté lo siguiente, obtengo un valor de protocolo diferente: 17. Es posible que también desee investigar esto.

Y, por supuesto, socket.has_ipv6 es cierto para mí.

La otra cosa que falta en lo anterior es que fe80 :: * son direcciones locales de enlace. Por lo tanto, técnicamente no se pueden usar sin una ID de ámbito.
En caso de que no se haya incluido, ” link-local ” significa que la dirección solo se puede usar en un enlace específico, pero el corolario es que dado que la dirección es teóricamente específica del enlace, podría tener esa misma dirección en más de un enlace.
Ahora se concede que, en la mayoría de los casos, se genera una dirección de enlace local desde la dirección de hardware ya única (EUI-48) al convertirla en un EUI-64 y luego cambiar el bit U / L ( ver ), pero esta no es la única La forma en que puede generar una dirección de enlace local y otros mecanismos podría resultar en la reutilización de la dirección (no creo que haya nada que lo prohíba). Así que ahora sabes por qué no funcionó.
La siguiente pregunta es cómo lo arreglas o, más bien, de dónde obtienes el ID de scope. Lamentablemente esto no es obvio. Si lee los RFC de IPV6 que tratan sobre ” Scope “, encontrará que está definido de manera general. En la práctica, si está ejecutando este código en Linux (¿quizás también en Windows / Mac?) Puede usar el índice de la interfaz.

Tenga en cuenta que actualmente hay un error en nss-mdns, por lo que los nombres de .local se devuelven con el ID de ámbito siempre a cero, por lo que en Linux el uso de los nombres de .local básicamente no funciona a menos que su código ya haya descubierto el ID de ámbito y lo establezca por sí solo.