在BSD和基於BSD系統。 (這包括MacOS X例如),作爲第二個16位字,作用域ID被嵌入到地址本身中作爲鏈接本地地址。請參閱FreeBSD Handbook並搜索「8.1.1.3範圍索引」(不帶引號)。
所以假設INTF1具有範圍編號1和intf2具有範圍ID 2,inet_pton()
將轉換爲字符串如下這些平臺:
"fe80::1234%intf1" -> fe80:1::1234
"fe80::1234%intf2" -> fe80:2::1234
"fe80::1234" -> fe80::1234
最後地址是根本無範圍,因而不能真正用於發送數據。
請注意,這是非標準的; inet_pton()
在基於Linux或Windows的系統上不能這樣工作。但是,我認爲即使在基於Linux和Windows的系統上,inet_pton()
也允許在最後使用作用域ID,但它會簡單地忽略它。
對於非鏈接本地地址,這個技巧當然不起作用,當然,這些地址通常沒有作用域。它們可以是範圍的,但通常每個接口都有一個基於其接口標識符的獨特接口IPv6地址(即使使用DHCPv6,在這種情況下,它也具有由DHCP服務器分配的DHCP地址,以及自動生成的IPv6接口地址,除非此自動生成已被禁止)。
struct sockaddr_in6
結構有一個作用域ID的字段,但定義此字段的RFC(RFC 2553 - Section 3.3)沒有給出有關該字段如何解釋的詳細信息。它只是說:
的sin6_scope_id的一個接口映射或一組接口被 留給執行情況和未來的規範上的 站點標識的主題。
所以這個字段完全是實現特定的。
如果你想在正確地填補了這一領域,你的代碼應該是跨平臺的可能,你應該使用getaddrinfo()
:
struct addrinfo hints;
struct addrinfo * result;
memset(&hints, 0, sizeof(hints));
// AI_NUMERICHOST prevents usage of DNS servers,
// it tells getaddrinfo that the input string is a numeric IP address.
hints.flags = AI_NUMERICHOST;
if (getaddrinfo("fe80::1234%intf1", NULL, &hints, &result) == 0) {
// result->ai_addr claims to be a pointer to struct sockaddr,
// in fact it will be a pointer to a struct sockaddr_in6 in our case.
struct sockaddr_in6 * so = (struct sockaddr_in6 *)result->ai_addr;
// It will be prefilled like this:
//
// so->sin6_family ==> AF_INET6;
// so->sin6_port ==> 0
// so->sin6_flowinfo ==> 0
// so->sin6_addr ==> fe80::1234
// so->sin6_scope_id ==> "intf1" as scope ID
// Do something with that sockaddr,
// e.g. set a port number and connect a socket to that address.
freeaddrinfo(result);
}
一個額外提示:如果您想使用返回getaddrinfo()
的服務器套接字(即要在本地綁定,然後調用它accept()
插槽),你還應該設置被動標誌:
hints.flags = AI_NUMERICHOST | AI_PASSIVE;
不,這將在大多數情況下作用,但也就是正確的方式使用getaddrinfo()
。
您的掃描碼被打破,它假定範圍ID是一個數字。雖然%1或%2是有效的範圍ID,但它們的含義完全取決於實施。範圍ID也可以是接口名稱,如%dc0,%eth0或%en0(取決於操作系統使用的名稱界面)。有關詳細信息,請參閱我的回覆,以瞭解如何獲取正確的作用域ID,即使是那些具有接口名稱 – Mecki 2012-12-11 18:58:41