2010-03-01 76 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。

相關問題