1. 程式人生 > >Linux網路程式設計之IPv6

Linux網路程式設計之IPv6

1.IPv6特點

我們已經學習過了流式套接字(SOCK_STREAM),資料報套接字(SOCK_DGRAM)和原始套接字(SOCK_RAWM),其中原始套接字的功能十分強大,能夠傳送自定義的資料包,偵聽網路上的資料,拒絕服務攻擊,傳送ICMP包等等。但這些協議都是基於IPv4,接下來,我們學習一下IPV6下的套接字程式設計. 下面介紹一個IPV6協議。相對於IPv4,IPv6有如下一些顯著的優勢:

(1)地址容量大大擴充套件,由原來的32位擴充到128位,徹底解決IPv4地址不足的問題;支援分層地址結構,從而更易於定址;擴充套件支援組播和任意播地址,這使得資料包可以傳送給任何一個或一組節點;

(2)大容量的地址空間能夠真正的實現無狀態地址自動配置,使IPv6終端能夠快速連線到網路上,無需人工配置,實現了真正的即插即用;

(3)報頭格式大大簡化,從而有效減少路由器或交換機對報頭的處理開銷,這對設計硬體報頭處理的路由器或交換機十分有利;

(4)加強了對擴充套件報頭和選項部分的支援,這除了讓轉發更為有效外,還對將來網路載入新的應用提供了充分的支援;

(5)流標籤的使用讓我們可以為資料包所屬型別提供個性化的網路服務,並有效保障相關業務的服務質量;

(6)認證與私密性:IPv6把IPSec作為必備協議,保證了網路層端到端通訊的完整性和機密性;

(7)IPv6在行動網路和實時通訊方面有很多改進。特別地,不像IPv4,IPv6具備強大的自動配置能力從而簡化了移動主機和區域網的系統管理。

2. IPv6地址型別

                在RFC1884中指出了三種類型的IPv6地址,他們分別佔用不同的地址空間:

               * 單點傳送:這種型別的地址是單個介面的地址。傳送到一個單點傳送地址的資訊包只會送到地址為這個地址的介面。

              * 任意點傳送:這種型別的地址是一組介面的地址,傳送到一個任意點傳送地址的資訊包只會傳送到這組地址中的一個(根據路由距離的遠近來選擇)

              * 多點傳送:這種型別的地址是一組介面的地址,傳送到一個多點傳送地址的資訊包會發送到屬於這個組的全部介面。

其中單播地址又包括:全域性可聚集的單播地址,站點本地地址和鏈路本地地址。
3  IPv6地址表示:

            對於128位的IPv6地址,考慮到IPv6地址的長度是原來的四倍,RFC1884規定的標準語法建議把IPv6地址的128位(16個位元組)寫成8個16位的無符號整數,每個整數用四個十六進位制位表示,這些數之間用冒號(:)分開,例如:3ffe:3201:1401:1:280:c8ff:fe4d:db39

希望手工管理IPv6地址的難度太大了,DHCP和DNS的必要性在這裡顯得更加明顯。為了簡化IPv6的地址表示,只要保證數值不變,就可以將前面的0省略。

比如:1080:0000:0000:0000:0008:0800:200C:417A

可以簡寫為:1080:0:0:0:8:800:200C:417A

另外,還規定可以用符號::表示一系列的0。那麼上面的地址又可以簡化為:1080::8:800:200C:417A

IPv6地址的字首(FP, Format Prefix)的表示和IPv4地址字首在CIDR中的表示方法類似。比如 0020:0250:f002::/48表示一個字首為48位的網路地址空間。

         注意: 0:0:0:0:0:0:0:1 稱為本地迴環地址

         鏈路本地地址:同一鏈路的相鄰節點的通訊,鏈路本地地址用於鄰居發現

        站點本地地址:在企業內部可以使用的地址,相當於私網地址.

        IPv6沒有廣播,它的功能正在被多播代替.

        IPv4相容地址: ::a.b.c.d 相容a.b.c.d.

 4. IPv6地址分配

        RFC1881規定,IPv6地址空間的管理必須符合Internet團體的利益,必須是通過一箇中心權威機構來分配。目前這個權威機構就是IANA(Internet Assigned NumbersAuthority,Internet分配號碼權威機構)。 IANA會根據IAB(Internet ArchitectureBoard)和IEGS的建議來進行IPv6地址的分配。

目前IANA已經委派以下三個地方組織來執行IPv6地址分配的任務:

       * 歐洲的RIPE-NCC(www.ripe.net)

      * 北美的INTERNIC(www.internic.net)

     * 亞太平洋地區的APNIC(www.apnic.net)

5. IPv6地址結構

struct sockaddr_in6{
 u_char sin6_len;
 u_char sin6_family;//協議族
 u_int16_t sin6_port;//埠號
 u_int32_t sin6_flowinfo;//設定流標記
  struct in6_addr sin6_addr;//地址
 u_int32_t sin6_scope_id;//設定IPv6地址作用範圍,是可聚集的全球化地址,還是本地站地址,還是鏈路地址

}
struct in6_addr{
 u_int8_t __u6_addr8[16];
}

in6addr_any表示本地任意地址.


6. IPv6客戶端與伺服器程式

伺服器:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
/**
IPv6伺服器端與客戶端設計
IPv6的地址結構
struct sockaddr_in6{
 u_char sin6_len;
 u_char sin6_family;//協議族
 u_int16_t sin6_port;//埠號
 u_int32_t sin6_flowinfo;//設定流標記
  struct in6_addr sin6_addr;//地址
 u_int32_t sin6_scope_id;//設定IPv6地址作用範圍,是可聚集的全球化地址,還是本地站地址,還是鏈路地址

}
struct in6_addr{
 u_int8_t __u6_addr8[16];
}
**/
#define PORT 8888
#define BACKLOG 10
int main(int argc,char*argv[]){
  int s;//伺服器套接字描述符
  int sc;//用於客戶端通訊的套接字描述符
  int ret;
  int size;
 struct sockaddr_in6 server_addr,client_addr;
  int len=sizeof(struct sockaddr_in6);
//建立套接字描述符
 s=socket(AF_INET6,SOCK_STREAM,0);  
 if(s==-1){
    perror("socket error");
   return -1;
 }
//繫結
 bzero(&server_addr,sizeof(server_addr));
 server_addr.sin6_family=AF_INET6;
 server_addr.sin6_port=htons(PORT);
 server_addr.sin6_addr=in6addr_any;//IPv6任意地址
 ret=bind(s,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret==-1){
   perror("bind error");
  return -1;
}
//監聽
ret=listen(s,BACKLOG);
if(ret==-1){
   perror("listen error");
    return -1;
 }
char buffer[1024];
//迴圈伺服器
while(1){
  time_t now;
 
  sc=accept(s,(struct sockaddr*)&client_addr,&len);
  if(sc==-1){
    perror("accept error");
       return -1;
 }
 memset(buffer,0,1024);
 inet_ntop(AF_INET6,&client_addr.sin6_addr,buffer,sizeof(buffer));
 
 printf("a client from IP:%s,port %d,socket %d\n",buffer,client_addr.sin6_port,sc);
memset(buffer,0,sizeof(buffer));
 size=recv(sc,buffer,1024,0);
if(size>0&&!strncmp(buffer,"TIME",4)){
 now=time(NULL);
 memset(buffer,0,sizeof(buffer));
 sprintf(buffer,"%24s\r\n",ctime(&now));
 send(sc,buffer,strlen(buffer),0);

}
close(sc);
}

close(s);

}

客戶端:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFFERSIZE 1024
int main(int argc,char*argv[]){
 int s;
 int ret;
 int size;
 char buffer[BUFFERSIZE];
 struct sockaddr_in6 server_addr;
 struct sockaddr_in6 client_addr;
//建立套接字
s=socket(AF_INET6,SOCK_STREAM,0);
 if(s<0){
   perror("socket error");
   return -1;
 }
//將地址結構繫結到套接字
 bzero(&server_addr,sizeof(server_addr));
 server_addr.sin6_family=AF_INET6;
 server_addr.sin6_port=htons(PORT);
 server_addr.sin6_addr=in6addr_any;//任意地址
//連線
 ret=connect(s,(struct sockaddr*)&server_addr,sizeof(server_addr));
//傳送請求
 memset(buffer,0,sizeof(buffer));
 strcpy(buffer,"TIME");
 size=send(s,buffer,strlen(buffer),0);
 if(size<=0){
   perror("send error");
   return -1;
 }
bzero(buffer,sizeof(buffer));
size=recv(s,buffer,BUFFERSIZE,0);
if(size>0){
    write(1,buffer,size);
 }
close(s);//關閉套接字描述符
}


執行結果:

./ipv6c

Sun Feb 19 20:21:31 2012

總結:本文主要介紹了IPv6特點以及與IPv4的不同點,最後給出了IPv6伺服器與客戶端的例項.