Linux下IPV6 Connect

最近在模拟测试IPv6客户端连接服务器(使用的是链路本地地址fe80::20c:29ff:fe98:77d2),但是总会报参数不正确,后来我使用strace追踪java-SocketTest(ipv6测试工具)的连接发现Connect需要初始化sin6_scope_id字段,才可以Connect success

struct sockaddr_in6
 {
    u_char sin6_len; 
    u_char sin6_family; 
    u_int16_t sin6_port; 
    u_int32_t sin6_flowinfo; 
    struct in6_addr sin6_addr;
    u_int32_t sin6_scope_id;
}
server_addr.sin6_scope_id = if_nametoindex("eth0");

sin6_scope_id is an ID depending on the scope of the address.  It is new in Linux 2.4.Linux supports it only for link-local addresses, in that case sin6_scope_id contains the interface index.

在IPv6地址结构中(对应于IPv4的struct sockaddr_in),有一个我们非常陌生的字段scope_id,这个字段在我们使用链路本地地址来编程的时候是必须要使用的,这个字段表示我们需要选择接口ID。为什么需要需要有这么一个字段,那是因为链路本地地址的特殊性,一个网络节点可以有多个网络接口,多个网络接口可以有相同的链路本地地址,例如我们需要bind一个本地链路地址,这个时候就会有冲突,操作系统无法决策需要绑定的是哪个接口的本地链路地址。又例如,如果我们在直连的2个主机之间直接用链路本地地址ping的话,会ping失败。因此IPv6引入了scope_id来解决这个问题,scope_id指定了使用哪个网络接口。

if_nametoindex函数定义:

#include <net/if.h>
unsigned if_nametoindex(const char *ifname);
char *if_indextoname(unsigned ifindex, char *ifname);
struct if_nameindex *if_nameindex(void);
void if_freenameindex(struct if_nameindex *ptr);

if_nametoindex():指定网络接口名称字符串作为参数;若该接口存在,则返回相应的索引,否则返回0

if_indextoname():指定网络接口索引以及一块长度至少为IF_NAMESIZE(16)字节的内存区域作为参数;若索引对应的网络接口存在,则在内存区域中返回该接口的名称字符串,否则返回NULL,并将errno设置为相应的值

if_nameindex():返回动态分配的struct if_nameindex结构数组,数组中的每一个元素分别对应一个本地网络接口;struct if_nameindex结构的if_index字段为接口索引,if_name字段为接口名称字符串;索引为0且名称字符串为NULL表示结构数组的末尾;调用出错时,返回NULL,并将errno设置为相应的值

if_freenameindex():通过if_nameindex()获取完毕接口名称与索引后,调用该函数以释放动态分配的内存区域。

猜你喜欢

转载自blog.csdn.net/qq_34870631/article/details/80585632