在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