C++ Socket编程中,
如果客户端要向服务端进行IPv6通信,
如果使用的是global 地址(2409::开头的),直接设置sin6_addr就可以,
如果使用的是链路本地地址(fe80::开头的),就需要设置sin6_scope_id才能通信。
sin6_scope_id实际上是网卡的索引号码。
可以用ip addr来查看网口索引
可以用netsh interface ipv6 show route来查看网口索引
首先用gethostname() 获取本地hostname,然后用getaddrinfo() 获取hostname的IP地址信息,这里面的IPv6信息会包括网口索引。
//get local host name
char errmsg[256] = { 0x00 };
struct in_addr addr;
char local_host_name[256] = { 0x00 };
if (gethostname(local_host_name, 256))
{
std::cout << "Get local host name failed, err:" <<
strerror_s(errmsg, 256, WSAGetLastError()) << std::endl;
return false;
}
std::cout << "local_host_name:" << local_host_name << std::endl;
std::cout << std::endl;
struct addrinfo hints, * res = NULL, * p = NULL;
memset(&hints, 0, sizeof(hints));
int e;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
e = getaddrinfo(local_host_name, NULL, &hints, &res);
if (e != 0)
{
std::cout << "get local addrinfo error:" << WSAGetLastError() << std::endl;
return false;
}
p = res;
char bufff[512] = { 0x00 };
while (p != NULL)
{
if (p->ai_family == AF_INET)
{
std::cout << "support IPv4" << std::endl;
memset(bufff, 0x00, sizeof(bufff));
inet_ntop(AF_INET, &((sockaddr_in*)p->ai_addr)->sin_addr, bufff, sizeof(bufff));
std::cout << "local support IPv4 addr:" << bufff << std::endl;
}
else if (p->ai_family == AF_INET6)
{
std::cout << "support IPv6" << std::endl;
memset(bufff, 0x00, sizeof(bufff));
inet_ntop(AF_INET6, &((sockaddr_in6*)p->ai_addr)->sin6_addr, bufff, sizeof(bufff));
sockaddr_in6* pv6 = (sockaddr_in6*)p->ai_addr;
ULONG scopeid = pv6->sin6_scope_id;
std::cout << "local support IPv6 addr:" << bufff << std::endl;
std::cout << "ipv6 socopeid:" << ((sockaddr_in6*)p->ai_addr)->sin6_scope_id << std::endl;
this->local_ipv6_scope_id = ((sockaddr_in6*)p->ai_addr)->sin6_scope_id;
ret = true;
}
p = p->ai_next;
}
freeaddrinfo(res);
输出结果:
是可以返回非0的网口索引的。(sin6_scope_id 设置为0 ,是无法进行链路本地地址通信的)
这里有一点要注意,如果getaddrinfo设置了hints.ai_flags = AI_PASSIVE;,那获取的是用于bind的任意地址,这个地址信息中是没有网口索引的。
struct addrinfo hints, * res = NULL, * p = NULL;
memset(&hints, 0, sizeof(hints));
int e;
hints.ai_flags = AI_PASSIVE;
e = getaddrinfo(NULL, "8080", &hints, &res);
if (e != 0)
{
std::cout << "get local addrinfo error:" << WSAGetLastError() << std::endl;
return false;
}
p = res;
char bufff[512] = { 0x00 };
while (p != NULL)
{
if (p->ai_family == AF_INET)
{
std::cout << "support IPv4" << std::endl;
memset(bufff, 0x00, sizeof(bufff));
inet_ntop(AF_INET, &((sockaddr_in*)p->ai_addr)->sin_addr, bufff, sizeof(bufff));
std::cout << "local support IPv4 addr:" << bufff << std::endl;
}
else if (p->ai_family == AF_INET6)
{
std::cout << "support IPv6" << std::endl;
memset(bufff, 0x00, sizeof(bufff));
inet_ntop(AF_INET6, &((sockaddr_in6*)p->ai_addr)->sin6_addr, bufff, sizeof(bufff));
sockaddr_in6* pv6 = (sockaddr_in6*)p->ai_addr;
ULONG scopeid = pv6->sin6_scope_id;
std::cout << "local support IPv6 addr:" << bufff << std::endl;
std::cout << "ipv6 socopeid:" << ((sockaddr_in6*)p->ai_addr)->sin6_scope_id << std::endl;
this->local_ipv6_scope_id = ((sockaddr_in6*)p->ai_addr)->sin6_scope_id;
ret = true;
}
p = p->ai_next;
}
freeaddrinfo(res);
return ret;
结果:网口索引是0,不能用于链路本地地址通信
使用if_nameindex()或者getifaddrs() 遍历网口,获取网口名字。-> C语言getifaddrs()通过网口IP获取网口名
然后使用if_nametoindex() 根据网口名,获取网口名的索引。->[IPv6] socket IPv6编程 connect()连接不上的问题
可能是我菜鸡,没找到。