91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Socket編程從IPv4轉向IPv6支持

發布時間:2021-09-10 17:38:51 來源:億速云 閱讀:219 作者:柒染 欄目:大數據

這篇文章給大家介紹如何使用Socket編程從IPv4轉向IPv6支持,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

目前運行主流的IT系統中,用于解決分布式系統內部模塊及不同的系統間通信的一種主要的解決方案就是使用套接字Socket來開發應用。由于當前大部分正在運行的IT系統中使用套接字Socket開發環境基本上都是基于IPv4完成的,因此在IT系統由IPv4向IPv6演進方案中如何完成這部分相關應用的演進就顯得尤為的關鍵

1. 基于SOCKET技術的接口協議

通常用BSD Socket API (Windows平臺用Win Socket API)作為基礎開發應用協議。以下是IT系統常用的接口協議:

基于SOCKET技術的接口協議通常以SOKET API作為為基礎開發應用協議,下表是IT系統常用的接口協議:
序號 協議名稱 類型
1 TELNET TCP
2 SSH TCP
3 FTP TCP
4 TFTP TCP
5 SNMP UDP
6 SOCKET自定義 TCP/UDP,IT系統或廠商基于SOKET API定義的私有協議

Telnet協議是TCP/IP協議族中的一員,是Internet遠程登陸服務的標準協議。應用Telnet協議能夠把本地用戶所使用的計算機變成遠程主機系統的一個終端。它提供了三種基本服務:
(1) Telnet定義一個網絡虛擬終端為遠的系統提供一個標準接口。客戶機程序不必詳細了解遠的系統,他們只需構造使用標準接口的程序;
(2) Telnet包括一個允許客戶機和服務器協商選項的機制,而且它還提供一組標準選項; .
(3) Telnet對稱處理連接的兩端,即Telnet不強迫客戶機從鍵盤輸入,也不強迫客戶機在屏幕上顯示輸出。

SSH的英文全稱是Secure Shell。通過使用SSH,你可以把所有傳輸的數據進行加密,這樣“中間人”這種攻擊方式就不可能實現了,而且也能夠防止DNS和IP欺騙。還有一個額外的好處就是傳輸的數據是經過壓縮的,所以可以加快傳輸的速度。 SSH有很多功能,它既可以代替telnet,又可以為ftp、pop、甚至ppp提供一個安全的“通道”。

從客戶端來看,SSH提供兩種級別的安全驗證: 第一種級別(基于口令的安全驗證)只要你知道自己帳號和口令,就可以登錄到遠程主機。所有傳輸的數據都會被加密,但是不能保證你正在連接的服務器就是你想連接的服務器。可能會有別的服務器在冒充真正的服務器, 也就是受到“中間人”這種方式的攻擊。第二種級別(基于密匙的安全驗證)需要依靠密匙,也就是你必須為自己創建一對密匙,并把公用密匙放在需要訪問的服務器上。如果你要連接到SSH服務器上,客戶端軟件就會向服務器發出請求,請求用你的密匙進行安全驗證。服務器收到請求之后,先在你在該服務器的HOME目錄下尋找你的公用密匙,然后把它和你發送過來的公用密匙進行比較。如果兩個密匙一致,服務器就用公用密匙加密“質詢”(challenge)并把它發送給客戶端軟件。客戶端軟件收到“質詢”(CHAP)之后就可以用你的私人密匙解密再把它發送給服務器。用這種方式,你必須知道自己密匙的口令。但是,與第一種級別相比,第二種級別不需要在網絡上傳送口令。第二種級別不僅加密所有傳送的數據,而且“中間人”這種攻擊方式也是不可能的(因為他沒有你的私人密匙)。

FTP是TCP/IP協議組中的協議之一,它工作在TCP模型的應用層之上,使用TCP傳輸,FTP需要兩個端口,一個端口是作為控制連接端口,也就是21端口,用于發送指令給服務器端以及等待服務器端的響應;另一個端口是數據傳輸端口,端口號20(僅PORT模式),是用來建立數據傳輸通道的。

TFTP全稱為Trivial File Transfer Protocol,中文名叫簡單文件傳輸協議。大家可以從它的名稱上看出,它適合傳送“簡單”的文件。與FTP不同的是,它使用的是UDP的69端口,因此它可以穿越許多防火墻。不過它也有缺點,比如傳送不可靠、沒有密碼驗證等。雖然如此,它還是非常適合傳送小型文件的。

SNMP(Simple Network Management Protocol,簡單網絡管理協議)的前身是簡單網關監控協議(SGMP),用來對通信 <http://baike.baidu.com/view/15007.htm>線路進行管理。隨后,人們對SGMP進行了很大的修改,特別是加入了符合Internet < http://baike.baidu.com/view/11165.htm>定義的SMI和MIB <http://baike.baidu.com/view/141513.htm>:體系結構,改進后的協議就是著名的SNMP。SNMP的目標是管理互聯網  <http://baike.baidu.com/view/6825.htm>Internet上眾多廠家生產的軟硬件 <http://baike.baidu.com/view/25278.htm>平臺,因此SNMP受Internet標準網絡管理框架的影響也很大。現在SNMP已經出到第三個版本的協議  <http://baike.baidu.com/view/36190.htm>,其功能較以前已經大大地加強和改進了。

SNMP的體系結構是圍繞著以下四個概念和目標進行設計的:保持管理代理(Agent)的軟件成本盡可能低;最大限度地保持遠程管理的功能,以便充分利用Internet的網絡資源 <http://baike.baidu.com/view/8439.htm>;體系結構  <http://baike.baidu.com/view/1188494.htm>必須有擴充的余地;保持SNMP的獨立性 <http://baike.baidu.com/view/562176.htm>,不依賴于具體的計算機  <http://baike.baidu.com/view/3314.htm>、網關 <http://baike.baidu.com/view/807.htm>和網絡傳輸協議 <http://baike.baidu.com/view/16807.htm>。

2. SOCKET API接口的差異性:

基于套接字Socket API所開發的應用中,基本上都使用相同的編程模型,且所有通信的基本操作如connect、accept、listen、send/sendto、read/readfrom等都是通過Socket API函數來完成的。這一點無論在IPv4的網絡環境下還是IPv6的網絡環境下基本上都是一致的,這就保證了基于套接字Socket開發的應用軟件在軟件結構上基本沒有變化,IPv4向IPv6演進所帶來的變化主要集中在那些與地址相關的API函數上(包括地址有關的數據結構體)。RFC2553針對IPv6帶來的套接字Socket API函數上的變化有明確的定義,IPv4和IPv6體現在套接字Socket API函數級別的差異可以用下面的表格來表示:

映射項 功能說明 IPv4 IPv6
常量定義 地址族 AF_INET AF_INET6
  協議族 PF_INET PF_INET6
IP地址結構體 結構體 sockaddr_in sockaddr_in6
 結構體成員:套接口長度 sin_len sin6_len
 結構體成員:協議族 sin_family sin6_family
 結構體成員:端口號 sin_port sin6_port
地址 通配地址 INADDR_ANY in6addr_any
 環回地址 INADDR_LOOPBACK in6addr_loopback
地址-表達式轉換函數 字符串地址轉為IP地址 inet_aton( ) inet_pton( )
 IP地址結構轉為字符串 inet_ntoa( ) inet_ntop( )
名字-地址轉換函數 根據名字獲得IP地址 gethostbyname() getaddrinfo()
 根據IP地址獲得名字 gethostbyaddr() getnameinfo()
 根據名字獲得IP地址 gethostbyname2() getaddrinfo()
 根據服務名獲得全部服務信息 getservbyname() getaddrinfo ()
 根據服務端口獲得全部服務信息 getservbyport() getaddrinfo()

那些使用C/C++等語言開發的應用軟件基本上主要關注這些API函數及結構體的變化就可以了。

JAVA作為主要編程語言的情況:

Java是目前IT系統廣泛使用的程序設計語言,在JDK的java.net包中(包括javax.net包)提供了完整的對套接字Socket編程的類定義,使用Java語言開發的應用都是基于這些類來完成的。JDK 從1.4版本開始部分支持IPv6協議,到了JDK1.5、JDK1.6就完全支持IPv6協議棧。現網調研的結果表明大多的IT系統都是可以運行在JDK1.5或以上的版本中。因此我們可以認為目前我們使用的JDK就已經具備了IPv6的能力。在JDK中和IPv4及IPv6相關的類只有兩個:java.net.Inet4Address和java.net.Inet6Address,  也就是說如果要區分IPv4和IPv6的話,通過區分這兩個類就可以了,而且這兩個類均繼承自同一個父類java.net.InetAddress,在JDK中,和套接字Socket相關的其他所有的類都僅僅與這個父類java.net.InetAddress相關(都應用的該類),而與IPv4(java.net.Inet4Address)及IPv6(java.net.Inet6Address)沒有直接的關系,即這些類對于是IPv4還是IPv6是透明的,因此從套接字Socket API接口這個層面上來看沒有差異。

3. 軟件重構涉及到的主要技術

通過上面的分析,我們知道了IPv4向IPv6演進所帶來的套接字Socket API接口上的差異,在了解及關注這些差異的基礎上,我們通過一些關鍵技術點的分析幫助我們重構軟件代碼以實現向IPv6的演進。
在使用C/C++語言來開發的Socket軟件中,主要關注以下幾個技術關鍵點:

3.1 地址結構的變化

IPv4環境下,通常使用的地址結構體sockaddr_in在頭文件中定義如下:

struct sockaddr_in{
 short int sin_family;
 unsigned short int sin_port;
 struct in_addr sin_addr; 
 unsigned char sin_zero[8];
};

struct in_addr{
 unsigned long s_addr; 
};


面向IPv4編程的socket編程中,針對上述地址結構體的賦值example如下:

rcv_udp_addr.sin_family = AF_INET;
rcv_udp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
rcv_udp_addr.sin_port = htons(UDPRCV_PORT);

IPv6環境下,地址結構體的發生對應的變化,定義如下:

struct sockaddr_in6 {
 uint8_t sin6_len;  
 sa_family_t sin6_family;
 in_port_t sin6_port; 
 uint32_t sin6_flowinfo; 
 struct in6_addr sin6_addr; 
 uint32_t sin6_scope_id;    
};

struct in6_addr {
 uint8_t s6_addr[16];
};

相對的對于IPv6地址結構體的賦值如下:

rcv_udp_addr.sin6_family = PF_INET;
rcv_udp_addr.sin6_addr.s6_addr =in6addr_any;
rcv_udp_addr.sin6_prot = htons (UDPRCV_PORT);

需要注意的是地址在IPv4中的地址結構體中sin_addr是主機字節順序(經過htons()函數轉換),
而在IPv6中,直接使用的是網絡字節順序。

3.2 socket的創建

建立socket的連接的API函數定義原型如下:
int socket(int domain,int type,int protocol);

對于IPv4而言,domain=AF_INET, 而IPv6,則domain=PF_INET6
例如創建TCP的Socket語句如下:

sock_tcp_ipv4 = socket(AF_INET,SOCK_STREAM,0);
sock_tcp_ipv6 = socket(PF_INET6,SOCK_STREAM,0);

3.3 字符串地址和網絡順序IP地址的相互轉換

在IPv4環境中,使用int inet_aton(const char *cp, struct in_addr *np)來完成從字符串地址到IP地址的轉換,在IPv6環境中,使用int inet_pton(int Af,const char *src,void *dst),多一個輸入參數,使用樣例:inet_pton(AF_INET6,hostname,&snd_tcp_addr.sin6_addr);

反之,當由網絡順序的IP地址轉換為字符串的時候,IPv4中,使用char *inet_ntoa(struct in_addr_in)而在IPv6環境中,使用const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt)這個函數,參數發生了明顯的變化,使用樣例:
inet_ntop(PF_INET6, &rcv_udp_addr_sin6_addr,ip,sizeof(ip));

3.4 主機名和地址的轉換(域名解析)

在IPv4環境中,使用gethostbyname()或者gethostbyaddr()函數來實現轉換;在IPv6環境中,則使用getnameinfo()或者getaddrinfo()函數來完成轉換,需要包含以下的三個頭文件:

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

3.5 組播地址常量

對于組播的應用,在IPv6環境下增加了一些常量的定義,在調用套接字Socket API相關函數的時候使用。代碼重構的時候,關注的常量如下表所示:
     常量 IPv6
IPV6_MULTICAST_IF 設置某個網絡接口為發送組播數據報的接口
IPV6_MULTICAST_HOPS 對于發送出的組播數據報為其設置hop的范圍
IPV6_MULTICAST_LOOP 如果組播源本身也屬于所發送出的組播數據的目標組播組,并且該選項設置為1的話,將會存本地發送的時候產生回環。該選項的缺省值為1
IPV6_JOIN_GROUP 加入組播組
IPV6_LEAVE_GROUP 離開組播組
 樣例代碼:
rc=setsockopt(s,IPPROTO_IPV6,IPV6_MULTICAST_HOPS,(char )&gTtl,sizeof(gTt1));

以上的幾個技術關鍵點適合于Unix、Linux平臺下的C/C++語言來開發的Socket軟件的重構。相對于Windows平臺,以上幾點基本上也是適合的(畢竟Winsock庫還是基本兼容標準的Socket API定義的),但是相對于Windows平臺在重構代碼是需要多注意下面幾點特殊性:

(1) 確保Winsock庫的版本在2.2或以上
對于Windows平臺而言,只有Winsock庫在2.2以上才支持IPv6。
(2) IP地址信息存儲
 在Winsock2庫中,使用新的SOCKADDR_STORGE結構體來存儲地址信息,這樣可以屏蔽IPv4地址和IPv6地址差異。
(3) 套接字Connect操作
 在Winsock2庫中,為了兼容IPv4和IPv6,,提供了兩個新的Connect函數(WSAConnectByName()和WSAConnectByList())用于建立Socket連接,與標準的connect()函數相比,這兩個Connect函數的優勢在于IP地址可以是IPv4的地址,也可以是IPv6的地址。


在現場調研的過程中,我們也發現了許多的IT系統在使用使用C/C++語言開發Socket軟件的時候,并不是直接使用原始的套接字Socket API函數或在此基礎上的封裝的庫來完成的,而是使用了第三方的庫來完成的,這里我們對常用的用于網絡編程第三方的庫也進行相關的分析。

在Linux、Unix及 Windows平臺下,ACE(The Adaptive Comunication Environment)是一個被廣泛用來進行網絡應用開發的軟件包,ACE軟件包從5.3版本開始就提供了對IPv6的支持,ACE軟件包中提供的有關IP地址封裝的類是ACE_INET_Addr,該類屏蔽了IP地址不同版本(IPv4、IPv6)的區別,相應類的成員方法也都兼容了不同地址版本,因此建立在ACE軟件包基礎上進行的網絡應用的開發是不需要做這種區分的(輸入的地址是IPv4的地址,則ACE_INET_Addr實例化的是具備IPv4特性的實例,輸入地址是IPv6的地址,則ACE_INET_Addr實例化的是具備IPv6特性的實例),  在重構代碼過程中重點需要關注的是當前ACE庫是否具備了支持IPv6的能力,即檢查編譯ACE庫的時候是否定有#ACE_HAS_IPV6宏定義。

相對于C/C++開發的Socket應用程序而言,使用Java程序設計語言開發的Socket應用程序在從IPv4環境重構到IPv6環境中基本上不需要做什么代碼的重構,這主要取決于JDK目前的版本已經提供了對IPv6的支持且有關IP地址的差異(IPv4和IPv6)已經被屏蔽(上一節已經進行了分析JDK類庫的情況),例如下面的代碼:
Socket echosocket = new Socket(“hostip”,7);
如果”hostip”對應的是IPv4的地址,則echosocket 是IPv4類型的Socket,如果”hostip”對應的是IPv6的地址,則echosocket是IPv6類型,一條語句對于這兩種地址類型都適應。


雖然JDK對于我們提供了很多的方便,使得我們的代碼基本上不需要重構,但是還是有兩個問題需要考慮:

1) Java虛擬機運行的操作系統環境
 必須確保JVM所運行的操作系統環境支持IPv6, 以Sun的JVM為例,要向支持IPv6, 對于操作系統的要求如下:
(1) Solaris 8 或更高的版本;
(2) Linux Kernel 2.1.2或更高版本(2.4.0版本以上可以更好的支持);
(3) Windows XP sp1、Windows 2003或更高的版本。
相對于其他的JVM(例如IBM的JVM、Oracle的JRockit等)需要檢查相應的對主機操作系統的要求。

2) 如何分是IP4和IPv6的地址

雖然大部分Java開發的應用中都不用關心到底是用的是IPv4的地址還是IPv6的地址,在某些情況下,例如需要輸出連接的IP地址信息或者需要獲得地址信息的詳細內容,這個時候是需要區分的。前面已經分析過java.net包中大部分類的成員函數使用的地址類是java.net.InetAddress,這個類是java.net.Inet4Address和java.net.Inet6Address類的父類,因此可以通過檢查java.net.InetAddress的子類類型來確認到底地址使用的是IPv4的地址還是IPv6的地址,樣例代碼如下:

     InetAddress  address = Socket.getInetAddress();
     if ( address  instanceof  java.net.Inet4Address ) {
        Inet4Address  address_ipv4 = (java.net.Inet4Address)address;
        address_ipv4.getAddress();
……… //相關的IPv4的地址操作
    } else if ( address  instanceof  java.net.Inet6Address ) {
        Inet6Address  address_ipv6 = (java.net.Inet6Address)address;
        address_ipv6.getScopeId();
……..//相關的IPv6地址操作
        } else {
            ……….
        }

 由于JDK所提供的有關套接字Socket相關的類非常的完善,基本上有關Java語言開發Socket應用很少使用第三方的包來完成。即使是那些建立在java.net包基礎上的應用于更高層協議應用第三方的包,例如Apache Commons中的Net包,該軟件包封裝了ntp、smtp、ftp、telnet、pop3等上層協議,也都是秉承了java.net包的特色,在軟件包中使用java.net.InetAddress作為地址類型,從而屏蔽了IPv4和IPv6的差異,使得功能上都同時支持IPv4環境和IPv6環境。


1.1.1.1. IPv4/IPV6雙棧實現方式
本文前面已經分析認為從IPv4向IPv6演進的最佳解決方案是IT系統提供對雙棧應用的支撐,下面將對如何使得那些基于套接字Socket技術實現的接口支持雙棧進行重點分析。

目前的IT系統大都是建立在操作系統上層的應用軟件,要想應用系統支持IPv4及IPv6雙棧,操作系統首先要支持雙棧,因此在重構應用軟件之前,確認或升級操作系統至支持雙棧是必要條件。

前面已經分析過基于套接字Socket技術實現的接口都采用相同的編程模式,即典型的客戶-服務器模式(Client-Server),針對于服務器端而言,雙棧模式下服務器端Socket應該能夠同時對綁定的IPv4地址及IPv6地址進行監聽,從而完成對不同地址的服務請求。想要達到這一目的可以有以下幾種方法:

1) 實施全地址監聽
針對服務端而言,如果將服務端監聽的地址綁定為”::”(IPv4中的0.0.0.0),將意味著服務器監聽系統地址列表中的所有地址,即無論是IPv4的地址還是IPv6的地址都將被服務器監聽以提供服務。例如下面的代碼:
int port = 1099;
ServerSocket  server = new ServerSocket(port);
Socket s ;
while (true) {
        S = server.accept();
        doClientStuff(s);
       }
服務器端將監聽地址列表中(無論IPv4地址還是IPv6地址)所有地址的1099端口,客戶端無論訪問的是IPv4的地址還是IPv6的地址,只要端口是1099,都將獲得服務器端的服務。
顯然,這種模式是一種最簡單的重構模式。

2) 兼容IPv4的IPv6地址
服務器端監聽的IPv6地址是兼容地址(地址模式為::w.x.y.z)或者是IPv4映射的地址(地址模式為::ffff:w.x.y.z),那么在雙棧模式下,服務器實際上是對兩個地址進行監聽,例如,服務器端綁定監聽的IPv6地址是::ffff:192.158.112.8, 那么實際上服務器對”::ffff:192.158.112.8”這個IPv6的地址進行監聽,同時也對192.158.112.8這個地址進行監聽,客戶端Socket訪問的目標地址無論是192.158.112.8這個IPv4地址,還是訪問”::ffff:192.158.112.8”這個IPv6的地址,服務端都可以提供服務。

3) IPv4地址與IPv6地址各自獨立
服務端需要監聽的地址是兩個完全獨立的IPv4地址及IPv6地址,此時通過分別對兩個不同的地址分別監聽來完成雙棧應用支撐,參見下面的樣例代碼:

  SOCKET   ServerSocket[FD_SETSIZE];
  ADDRINFO  AI0;// 存儲的是IPv6的地址
 ADDRINFO  AI1;// 存儲的是IPv4的地址

  ServerSocket[0] = socket(AF_INET6, SOCK_STREAM,PF_INET6);
   ServerSocket[1] = socket(AF_INET, SOCK_STREAM,PF_INET);
   ………..
   bind(ServerSocket[0], AI0->ai_addr,AI0->ai_addrlen);
   bind(ServerSocket[1], AI1->ai_addr,AI1->ai_addrlen);
   …………
   select (2, &ServerSet, 0, 0, 0); // select()系統調用:異步I/O多工

   if ( FD_ISSET(ServerSocket[0], &ServerSet) ) {
      //IPv6連接   sockv6 = accept(….)
     …….
   }
   if ( FD_ISSET(ServerSocket[1], &ServerSet) ) {
      //IPv4 連接  sockv4 = accept(…..)
      …..
  }

顯然,這種模式是一種比較復雜的重構模式。

    與服務器端復雜的重構方案相比,客戶端的改造就會相對簡單,在一個支持雙棧應用的系統中,客戶端每一個Socket連接實例,都只會在IPv4模式及IPv6模式間選擇一種,這種選擇可以通過相應的配置文件來完成,每一次創建客戶端Socket實例之前,依據從配置文件中讀取出的服務端地址類型(或者自動分析地址格式來獲得類型)配置項來決定創建哪一種類型的Socket實例。相對于Java開發的客戶端而言,由于JDK對IPv6很好的適應性(前面已經分析過),代碼幾乎不需要做重構,相對于C/C++開發的客戶端而言,需要根據不同服務端IP地址的類型,使用不同的地址結構體及參數等來創建Socket實例(關鍵技術一節已經分析)。

 對于實際運行環境是單棧的系統,分別對IPv4和IPv6開發出不同的版本是不可取的。通常的解決方案(無論是客戶端還是服務端)和雙棧環境下客戶端的解決方案相類似,即通過選擇配置文件選擇項來確定當前實例的運行環境是IPv4環境還是IPv6環境。

關于如何使用Socket編程從IPv4轉向IPv6支持就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

尚志市| 临清市| 平定县| 新平| 安吉县| 宁都县| 如东县| 五台县| 元朗区| 郧西县| 桦南县| 三穗县| 大城县| 毕节市| 阿拉善右旗| 河源市| 景泰县| 宣武区| 虹口区| 江山市| 象州县| 曲麻莱县| 上蔡县| 高安市| 蕉岭县| 犍为县| 伊吾县| 子长县| 大理市| 定日县| 青川县| 建始县| 淳安县| 乌审旗| 温泉县| 汽车| 璧山县| 临沭县| 财经| 冷水江市| 肃北|