实际上我正在将IPv4服务器应用程序移植到Linux上的双栈IPv4 / IPv6应用程序 .
我通过使用解决的基本功能:
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_addr = in6addr_any;
...
bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
...
listen(sock, 5);
...
newsock = accept(syn->sock, (struct sockaddr *) &cli_addr, &clilen);
我可以连接IPv4和IPv6并使用连接 . 但是当我想获得IP时:
switch(data->sa_family) {
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in*)data)->sin_addr), buffer, size);
break;
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6*)data)->sin6_addr), buffer, size);
break;
default:
buffer[0] = '?';
buffer[1] = 0;
}
我总是按预期获得IPv6地址,或者如果它是类似:: ffff:127.0.0.1的IPv4连接
我需要更改什么,以127.0.0.1(没有:: ffff:-prefix)的形式显示为普通的旧IPv4地址?
谢谢泰迪
3 回答
你有两种方法可以去:
只需从头开始删除此
::ffff:
(如果存在),并将其作为IPv4的指示符 .使用两个不同的套接字 . 那里有操作系统不支持IPv4和6通过一个插槽(IOW,他们总是启用_1566006) . 特别是,WinXP就这样做了 .
那么你只能做一件事:
使用带有
AI_PRIVATE
的getaddrinfo()
获取您可以拥有的所有本地套接字地址如果可能,使用all all创建侦听套接字并立即启用
V6ONLY
将它们的描述符保存在数组中并使用
select()
等确定它们中的哪一个调用accept()
.听起来比实际更复杂......
您请求呈现IPv4映射连接,就好像它们实际上是IPv4,代码如下所示:
这需要针对每个新的客户端套接字进行 . IPv6连接失败;您可以忽略它或先检查,只有在使用IPv4映射客户端时才调用它 .
完成后,您可以调用
getpeername()
以首选格式获取客户端地址信息,而不是将其作为调用accept()
的一部分 .有一个宏可以帮助,但只有一半的战斗:
根据平台可能需要进行少量修改,这里使用GNU标准 .