2010-03-01 77 views
8

我需要将IPv6支持添加到当前仅支持IPv4的现有基于套接字的应用程序。为了迎接即将到来的IPv6时代,有人命令我为应用程序添加IPv6接口,并让外部世界在尝试与应用程序通信时选择IPv4接口或IPv6接口。套接字级别的IPv4和IPv6有什么区别吗?

我的问题是:对于Linux中的套接字处理API级别,处理基于IPv4的套接字和基于IPv6的套接字没有区别吗?

此外,是否有可能让一个套接字侦听两个具有相同端口的IP地址?如果那是真的,那么执行这个要求是一件微不足道的工作,我想。

回答

6

无法使用1个TCP套接字监听2个不同的IP地址,但是如果您使用in6addr_any地址监听所有接口,那么也会包含所有IPv4地址(尽管我相信例如linux有内核选项禁用该映射)。

套接字API的(更新版本)对于您是使用IPv4还是IPv6来说是相当透明的,但必须非常小心如何对IPv4应用程序进行典型编码。

例如它接受一个连接并打印出远程主机的地址,这样的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/

+0

@nos:谢谢你的帮助。我还有一个问题,是否可以将udp套接字绑定到多个IP地址?例如,一个用于ipv4,一个用于ipv6,共2个。 –

+1

不,您无法将UDP套接字绑定到超过1个(或全部)IP地址。尽管如此,你可以使用它的多宿主功能。对于每个你想要监听的地址,你必须为每个地址创建一个socket,除非你想监听所有的ip地址 – nos

+0

要获得双栈套接字,有一个套接字选项可以启用或禁用双栈行为 - 搜索IPV6_V6ONLY获取更多信息。如果你不这样做,你的程序会在特定版本的某些操作系统上神秘失败。 – christopher

0

我相信有一个区别,主要是如何分配/显示IP地址和子网掩码。

采用传入IPv4地址的方法将不起作用,如果给予纯IPv6,则会抛出异常,因此您的方法需要检查启动了哪种连接,除此之外我不认为所以。

0

IPv6是128位地址空间,与IPv4(32位)相比,它提供更多功能(无状态,多播,更简单的路由器处理,仅举几例),但IPv4的地址空间已用尽NAT/SNAT的帮助可能会延长IPv4协议的使用寿命。使用IPv6取决于操作系统是否可以支持新协议。它当然可以在Windows 7,Linux上...主要是IPv6向后兼容IPv4 ...

要回答你的问题,这取决于API级别提供的操作系统可以支持IPv6网络堆栈,这里是MSDN的发现,为Linux的IPv6的一个例子例如插座,插座的使用主要是与你将使用异常的同...

希望这有助于 最好的问候, 汤姆。

4

对于IPv4和IPv6,大部分套接字处理都是相同的。在服务器上,一旦绑定了您的地址,对于IPv4和IPv6连接,对listen,accept,recvsend的调用都将相同。

但与地址处理任何功能,如connectbindgetsocknamegetpeername将需要被修改,因为你需要使用。此外,您需要修改与地址一起使用的功能(例如,需要将inet_addr的调用更改为inet_pton)。

在Linux上,如果你绑定到in6addr_any,同时支持IPv4和IPv6连接到该端口就可以了(尽管这可能会听多则2个地址,因为它也将在IPv4的环回127.0.0.1和IPv6回环::1听) 。但在Windows上,我从来没有能够实现这个目标,并且需要监听一个用于IPv4的套接字和另一个用于IPv6的套接字。

+3

在Windows中,通过重新设计的双堆栈套接字栈体系结构,Vista中引入了单个套接字在单个端口上监听和接受IPv4和IPv6客户端的能力。创建IPv6侦听套接字并将新的IPV6_V6ONLY套接字选项设置为False以允许其上的IPv4客户端。 –

+0

@RemyLeabeauTeamB - 谢谢 - 这些信息非常有帮助。 –

2

Beej的网络编程指南解决了IPv4和IPv6编码的差异。 http://beej.us/guide/bgnet/

他有专门的一节来改变你现有的IPv4代码来处理IPv6。

他还解释了如何在套接字级别进行抽象编码,以便您不需要知道您是在处理IPv4地址还是IPv6。

相关问题