2010-10-27 10 views
6

Hace aproximadamente una semana alguien en StackOverflow asked por qué su código de Python para conectarse a una dirección de enlace local IPv6 no funcionaba, y respondí que debido a que era una dirección de enlace local, necesitaban agregar un% en0 (o cualquiera que sea el nombre de interfaz local deseado) sufijo a su dirección IP de destino. Pensé que sabía de lo que estaba hablando, así que en realidad no probé mi sugerencia antes de responder (¡qué vergüenza!).¿Por qué no funciona un sufijo% en0 para conectar un socket TCP-local IPv6 TCP en Python?

Hoy fui a usar la misma técnica para mí, solo para descubrir que no parece funcionar. :^(Es decir, este código no funciona:

>>> from socket import * 
>>> s = socket(AF_INET6, SOCK_STREAM) 
>>> s.connect(('fe80::21f:5bff:fe3f:1b36%en0', 2001)) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 1, in connect 
socket.error: [Errno 65] No route to host 

El siguiente código, por el contrario, hace el trabajo (con o sin el sufijo en0%):

>>> from socket import * 
>>> s = socket(AF_INET6, SOCK_STREAM) 
>>> s.connect(('fe80::21f:5bff:fe3f:1b36%en0', 2001, 0, 6)) 
>>> 

... pero no me gusta hacerlo de esa manera, porque para averiguar qué ID de alcance suministrar para el último argumento, tengo que ejecutar un montón de código no muy portátil para iterar sobre la lista de interfaces locales, encontrar la interfaz denominada 'en0', y extraer su ID de ámbito, que es más sobrecarga de complejidad de lo que me gustaría tener.

Dado que connect() está aceptando el sufijo% en0 en la dirección IP, ¿por qué no se está utilizando realmente como se esperaba para determinar la ID del alcance?

FWIW, estoy probando con Python 2.6.1 bajo MacOS/X 10.6.4.

+0

En Windows, el ID de alcance de la NIC limitada local tiene prioridad sobre la que proporciona en la dirección de destino. :(Si no enlaza el socket intencionalmente primero, el sistema elige una NIC para usar. La identificación del alcance objetivo es ** una pista ** solamente. –

Respuesta

12

Ésta es la forma correcta de hacer una conexión IPv6:

>>> addrinfo = getaddrinfo('fe80::225:ff:fecd:5aa0%en0', 2001, AF_INET6, SOCK_STREAM) 
>>> addrinfo 
[(30, 1, 6, '', ('fe80::225:ff:fecd:5aa0%en0', 2001, 0, 4))] 
>>> (family, socktype, proto, canonname, sockaddr) = addrinfo[0] 
>>> s = socket(family, socktype, proto) 
>>> s.connect(sockaddr) 

getaddrinfo() devolverá el alcance numérico correcto y el flujo de información para usted.

Cuestiones relacionadas