2010-10-27 11 views
6

Jakiś tydzień temu ktoś na StackOverflow asked, dlaczego ich kod Pythona do połączenia z lokalnym adresem IPv6 nie działa, a ja odpowiedziałem, że ponieważ był to adres lokalny dla łącza, musieli dodać% en0 (lub bez względu na pożądaną nazwę interfejsu lokalnego) przyrostek do docelowego adresu IP. Myślałem, że wiem, o czym mówię, więc nie przetestowałem mojej sugestii przed udzieleniem odpowiedzi (wstyd mi!).Dlaczego sufiks% en0 nie działa, aby podłączyć lokalne gniazdo TCP IPv6 w Pythonie?

Dziś poszedłem użyć tej samej techniki dla siebie, ale okazało się, że nie działa. :^(To znaczy, ten kod nie działa:

>>> 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 

Poniższy kod, z drugiej strony, nie działa (z lub bez% en0 przyrostkiem):

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

... ale nie lubię robić tego w ten sposób, ponieważ w celu wykrycia, która liczba całkowita identyfikatora zakresu jest dostarczana dla ostatniego argumentu, muszę wykonać grupę niezbyt przenośnego kodu do iteracji na liście lokalnych interfejsów, znaleźć interfejs o nazwie "en0", i wyodrębnij jego identyfikator zakresu, który jest bardziej złożony narzut niż chciałbym mieć.Biorąc pod uwagę, że connect() akceptuje sufiks% en0 na adres IP, dlaczego w rzeczywistości nie używa go zgodnie z oczekiwaniami do określenia identyfikatora zakresu?

FWIW, testuję z Python 2.6.1 pod MacOS/X 10.6.4.

+0

W systemie Windows identyfikator powiązanej lokalnej karty NIC ma pierwszeństwo przed identyfikatorem zakresu podanego w adresie docelowym. :(Jeśli nie celowo najpierw zwiążesz gniazdo, system wybierze kartę sieciową, której docelowy identyfikator to ** podpowiedź **. –

Odpowiedz

12

Jest to poprawny sposób to zrobić połączenia 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() powróci prawidłowy zakres liczbowy i przepływu informacji dla Ciebie.