2010-10-27 18 views
6

大約一週前StackOverflow上的某人asked爲什麼他們連接到IPv6鏈接本地地址的Python代碼不起作用,並且我回答說,由於它是一個鏈接本地地址,他們需要添加一個%en0(或不管所需的本地接口名是什麼)後綴到它們的目標IP地址。我以爲我知道我在說什麼,所以在回答之前我沒有真正地測試我的建議(對我感到羞恥!)。爲什麼%en0後綴不能在Python中連接鏈接本地IPv6 TCP套接字?

今天我對自己使用了相同的技術,只是發現它看起來不起作用。 :^(也就是說,該代碼不起作用:

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

下面的代碼,在另一方面,沒有工作(帶或不帶%EN0後綴):

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

...但我不喜歡這樣做,因爲爲了弄清楚爲最後一個參數提供哪個範圍的ID整數,我必須執行一堆不太可移植的代碼來遍歷本地接口列表,找到名爲'en0'的接口,並提取它的作用域ID,這比我想要的更復雜。

鑑於connect()正在接受IP地址的%en0後綴,爲什麼它實際上沒有按預期使用它來確定作用域ID?

FWIW,我正在用MacOS/X 10.6.4下的Python 2.6.1進行測試。

+0

在Windows中,本地綁定的NIC的範圍ID優先於您在目標地址中提供的ID。 :(如果你不是先有意地綁定套接字,那麼系統選擇一個NIC來使用,目標範圍id只是**提示**。 – 2013-02-08 19:39:42

回答

12

這是正確的方式做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()將返回正確的數值範圍,爲你流信息。