我需要为现有的仅支持IPv4的基于套接字的应用程序添加IPv6支持。为了迎接即将到来的IPv6时代,有人命令我为应用程序添加IPv6接口,并在尝试与应用程序通信时让外界选择IPv4接口或IPv6接口。
我的问题是:对于Linux中的套接字处理API级别,处理基于IPv4的套接字和基于IPv6的套接字之间没有区别吗?
此外,是否可以让套接字侦听具有相同端口的两个IP地址?如果这是真的,那么实现这个要求是一项微不足道的工作,我想。
答案 0 :(得分:6)
使用1个TCP套接字无法监听2个不同的IP地址,但是如果使用in6addr_any地址监听所有接口,那么也会包含所有IPv4地址(尽管我相信例如linux已经一个内核选项来禁用该映射。)
(较新版本)套接字API对于您使用的是IPv4还是IPv6非常透明,但必须非常谨慎地处理IPv4应用程序的编码方式。
e.g。此IPv4代码接受连接并打印出远程主机的地址:
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len);
log_printf("New client from %s\n",inet_ntoa(client_addr.sin_addr.s_addr));
必须转换为以下处理IPv4和IPv6的
struct sockaddr_storage client_addr;
char numeric_addr[INET6_ADDRSTRLEN];
socklen_t addr_len = sizeof(client_addr);
client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len);
if(client_addr.ss_family == AF_INET)
log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in*)&client_addr)->sin_addr.s_addr ,numeric_addr,sizeof numeric_addr));
else if(client_addr.ss_family == AF_INET6)
log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in6*)&client_addr)->sin6_addr ,numeric_addr,sizeof numeric_addr));
虽然我相信你可以用getaddrinfo()
更优雅和透明地做到这一点以下是有关IP层独立性的附加说明: http://uw714doc.sco.com/en/SDK_netapi/sockC.PortIPv4appIPv6.html http://www.kame.net/newsletter/19980604/
答案 1 :(得分:4)
IPv4和IPv6的大部分套接字处理都是相同的。在服务器上,一旦绑定了地址,对listen
,accept
,recv
和send
的调用对于IPv4和IPv6连接都将起作用。< / p>
但是,任何处理connect
,bind
,getsockname
,getpeername
等地址的函数都需要修改,因为您需要使用{{1} }。此外,您需要修改使用地址的函数(例如,对sockaddr_in6
的调用需要更改为inet_addr
)。
在Linux上,如果绑定到inet_pton
,那么到该端口的IPv4和IPv6连接都将起作用(尽管这可以侦听超过2个地址,因为它也会侦听IPv4环回{{1}和IPv6环回in6addr_any
)。但是在Windows上,我从来没有能够让它工作,需要在一个插槽上侦听IPv4和一个不同的IPv6套接字。
答案 2 :(得分:2)
Beej的网络编程指南解决了IPv4和IPv6编码的差异。 http://beej.us/guide/bgnet/
他专注于改变现有IPv4代码以处理IPv6。
他还解释了如何在套接字级别抽象编码,这样您就不需要知道是在处理IPv4地址还是IPv6。
答案 3 :(得分:0)
我认为存在差异,主要是如何分配/显示IP地址以及子网掩码。
获取传入IPv4地址的方法将无效并且如果为其提供纯IPv6则抛出异常,因此您的方法将需要检查启动了哪种连接,除此之外我不这么认为
答案 4 :(得分:0)