1. 程式人生 > >IPv6之初使用,及IPv4與IPv6的socket通訊

IPv6之初使用,及IPv4與IPv6的socket通訊

1.IPv6概念

            IPv6InternetProtocol Version 6的縮寫。IPv6IETF(網際網路工程任務組,InternetEngineering Task Force)設計的用於替代現行版本IP協議(IPv4)的下一代IP協議。

2.IPv6與IPv4相比具有的優勢  

a,IPv6具有更大的地址空間。IPv4中規定IP地址長度為32,即有2^32-1個地址;而IPv6IP地址的長度為128,即有2^128-1個地址。

b,IPv6使用更小的路由表。IPv6的地址分配一開始就遵循聚類(Aggregation)的原則,這使得路由器能在路由表中用一條記錄(

Entry)表示一片子網,大大減小了路由器中路由表的長度,提高了路由器轉發資料包的速度。

c,IPv6增加了增強的組播(Multicast)支援以及對流的支援(FlowControl),這使得網路上的多媒體應用有了長足發展的機會,為服務質量(QoSQualityof Service)控制提供了良好的網路平臺。

d,IPv6加入了對自動配置(AutoConfiguration)的支援。這是對DHCP協議的改進和擴充套件,使得網路(尤其是區域網)的管理更加方便和快捷。

e,IPv6具有更高的安全性。在使用IPv6網路中使用者可以對網路層的資料進行加密並對IP報文進行校驗,極大的增強了網路的安全性。

3.IPv6的三種常規表示形式

1)十六進位制:3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562
    2)壓縮形式:例如,多路廣播地址 FFED:0:0:0:0:BA98:3210:4562 的壓縮形式為 FFED::BA98:3210:4562。單播地址3FFE:FFFF:0:0:8:800:20C4:0 的壓縮形式為 3FFE:FFFF::8:800:20C4:0。環回地址0:0:0:0:0:0:0:1 的壓縮形式為 ::1。未指定的地址 0:0:0:0:0:0:0:0 的壓縮形式為 ::。
     3)混合形式
此形式組合 IPv4 和 IPv6 地址。在此情況下,地址格式為 n:n:n:n:n:n:d.d.d.d,其中每個 n 都表示4個 IPv6 高序位 16 位地址元素之一的十六進位制值,每個 d 都表示 IPv4 地址的十進位制值。

4.IPv6 協議棧的安裝及 IPv6 地址設定

      a)windows下IPv6設定

      (1) IPv6 協議棧的安裝:在 開始 --> 執行 處執行 ipv6 install
      (2) IPv6 地址設定:在 開始 --> 執行 處執行 netsh 進入系統網路引數設定環境,然後執行interface ipv6。畫面顯示:netsh interface ipv6>然後再執行:add address “本地連線” 2001:f80:754::3
      (3) IPv6預設閘道器設定:在上述系統網路引數設定環境中執行:add route ::/0 “本地連線” 2001:f80:754::1 publish=yes
      (4) IPv6地址刪除:在 開始 --> 執行 處執行 netsh 進入系統網路引數設定環境,然後執行interface ipv6。畫面顯示:netsh interface ipv6>然後再執行:delete address “本地連線” 2001:f80:754::11 (注:必須以管理員身份執行CMD)

     b)linux下IPv6的設定(linux核心自2.2.0開始都是支援IPv6核心這個模組的)(1)手動新增IPv6地址和預設路由
          #ifconfig eth0 add 2001:f80:754::2/64  (或如下)
          #ifconfig eth0 inet6 add 2001:f80:754::2/64 
          #route -A inet6 add default gw 2001:f80:754::1/64 (配置時,沒有修改預設漏油也沒有出現過什麼問題!)    

          //#ifconfig eth0 del 2001:f80:754::2/64 (delete)

     (2)通過修改配置檔案/etc/rc.local,配置檔案下新增IPv6地址和預設路由
          #vi /etc/rc.local (開啟該檔案)
          #fconfig eth0 add 2001:f80:754::2/64 (IPv6地址)
          #route -A inet6 add default gw 2001:f80:754::1/64  (預設路由)

5.使用IPv4 及 IPv6 地址socket通訊的一些demo

     為了程式設計的方便,一般我喜歡把socket通訊有關的標頭檔案都包含進來,省得麻煩,如下的標頭檔案mynet.h

   <span style="font-size:12px;">/*mynet.h*/
    #include  <netinet/in.h>  
      
    #include  <sys/param.h>  
    #include  <sys/stat.h>  
    #include  <sys/ioctl.h>  
    #include  <sys/socket.h>  
    #include  <sys/socket.h>  
    #include  <sys/time.h>  
    #include  <sys/file.h>  
    #include  <sys/types.h>  
      
    #include   <netinet/ip.h>  
    #include  <arpa/ftp.h>  
    #include  <arpa/inet.h>  
    #include  <arpa/telnet.h>  
       
    #include  <stdio.h>  
    #include  <signal.h>  
    #include  <string.h>  
    #include  <net/if.h>  
    #include  <stdlib.h>  
    #include  <unistd.h>  
    #include  <error.h>  
    #include <ifaddrs.h>    
    #include  <netdb.h>  </span>

首先實現的是IPv4下的TCP連線,如下程式碼實現server:

/*tcpipv4serv.c*/
#include "mynet.h"
#define MyPort 10086
#define MyNum 20

int main(int argc,char* argv[]){
	int mysock;
	int clientfd;
	int bytes = 0;
	int len = sizeof(struct sockaddr_in);
	struct sockaddr_in myaddr;
	struct sockaddr_in cliaddr;
	char *sendbuf = "hello client,i have recv msg";
	char recvbuf[256];
	char clientip[INET6_ADDRSTRLEN];

	mysock = socket(AF_INET, SOCK_STREAM, 0);
	if(mysock < 0){
		printf("Error at socket().\n");
		return -1;
	}

	myaddr.sin_family = AF_INET;
	myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	myaddr.sin_port = htons(MyPort);

	if( bind(mysock, (struct sockaddr*)&myaddr, sizeof(myaddr)) < 0 ) {
		printf("bind() failed. \n");
		close(mysock);
		return -1;
	} 

	if(listen(mysock, MyNum) < 0) {
		printf("Error listening on socket.\n");
		close(mysock);
		return -1;
	}
             printf("server listen...\n");
	memset(&cliaddr, '0', sizeof(cliaddr));	
	for(;;){
		clientfd = accept(mysock,  (struct sockaddr*)&cliaddr,  &len);
		memset(recvbuf, '\0', sizeof(recvbuf));
		if( bytes = recv(clientfd, recvbuf, sizeof(recvbuf), 0) < 0 ) {
			printf("recv error!\n");
		} else {
			inet_ntop(AF_INET, &cliaddr.sin_addr, clientip, INET6_ADDRSTRLEN);
			printf("C:%s->S: %s\n", clientip, recvbuf);
			memset(recvbuf, '\0', sizeof(recvbuf));
			if( bytes = send(clientfd, sendbuf, strlen(sendbuf)+1, 0) < 0 ) {
					printf("recv error!\n");	
			} else {
					printf("S->C:%s\n", sendbuf);
			} 
		}
	}

	closesocket(mysock);
	closesocket(clientfd);
	return 0;
}

以下的程式碼是client端:

<span style="font-size:12px;">#include "mynet.h"
#define MyPort 10086

int main(int argc,char* argv[]){
	struct sockaddr_in servaddr;
	int mysock;
	int bytes = 0;
	int len = sizeof(struct sockaddr_in);
	char mybuff[256]; 
	if( argc != 3){
		printf("usage: <exe> <serverip> <port>\n");
		return -1;
	}
	
	mysock = socket(AF_INET, SOCK_STREAM, 0);
	if(mysock < 0){
		printf("Error at socket().\n");
		return -1;
	}
	
	memset(&servaddr, 0, len);
	servaddr.sin_family = AF_INET;
	//servaddr.sin_addr.s_addr = htonl(atol(argv[1]));
	inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
	servaddr.sin_port = htons(atoi(argv[2])); 

	if(connect(mysock,(struct sockaddr *) &servaddr, len) < 0){
		printf("connect error!\n");
		return -1;
	}
	memset(mybuff,0,sizeof(mybuff));			
 	printf("Client Send:");
 	gets(mybuff);
			
	bytes = send(mysock, mybuff, strlen(mybuff), 0);
	if( bytes>0 ){
		memset(mybuff,0,sizeof(mybuff));			
	}
	bytes = recv(mysock, mybuff, sizeof(mybuff), 0);
	if (bytes>0)
	{
		printf("client recv:%s\n", mybuff);
		memset(mybuff,0,sizeof(mybuff));			
	}
}</span>
通過使用gcc 命令分別編譯成tcpipv4serv和tcpipv4cli這兩個可執行檔案,如下圖

                                          圖1-1 執行tcp server

                                                  圖1-2執行tcp  client

一下將貼出IPv6的server和client

<span style="font-size:12px;">/*tcpipv6serv.c*/
#include "mynet.h"
#define MyPort 10086
#define MyNum 20

int main(int argc,char* argv[]){
	int mysock;
	int clientfd;
	int bytes = 0;
	int len = sizeof(struct sockaddr_in);
	struct sockaddr_in myaddr;
	struct sockaddr_in cliaddr;
	char *sendbuf = "hello client,i have recv msg";
	char recvbuf[256];
	char clientip[INET6_ADDRSTRLEN];

	mysock = socket(AF_INET, SOCK_STREAM, 0);
	if(mysock < 0){
		printf("Error at socket().\n");
		return -1;
	}

	myaddr.sin_family = AF_INET;
	myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	myaddr.sin_port = htons(MyPort);

	if( bind(mysock, (struct sockaddr*)&myaddr, sizeof(myaddr)) < 0 ) {
		printf("bind() failed. \n");
		close(mysock);
		return -1;
	} 

	if(listen(mysock, MyNum) < 0) {
		printf("Error listening on socket.\n");
		close(mysock);
		return -1;
	}
             printf("server listen...\n");
	memset(&cliaddr, '0', sizeof(cliaddr));	
	for(;;){
		clientfd = accept(mysock,  (struct sockaddr*)&cliaddr,  &len);
		memset(recvbuf, '\0', sizeof(recvbuf));
		if( bytes = recv(clientfd, recvbuf, sizeof(recvbuf), 0) < 0 ) {
			printf("recv error!\n");
		} else {
			inet_ntop(AF_INET, &cliaddr.sin_addr, clientip, INET6_ADDRSTRLEN);
			printf("C:%s->S: %s\n", clientip, recvbuf);
			memset(recvbuf, '\0', sizeof(recvbuf));
			if( bytes = send(clientfd, sendbuf, strlen(sendbuf)+1, 0) < 0 ) {
					printf("recv error!\n");	
			} else {
					printf("S->C:%s\n", sendbuf);
			} 
		}
	}

	closesocket(mysock);
	closesocket(clientfd);
	return 0;
}</span>
<span style="font-size:12px;">/*tcpipv6cli.c*/
#include "mynet.h"
#define MyPort 10086

int main(int argc,char* argv[]){
	struct sockaddr_in6 servaddr;
	int mysock;
	int bytes = 0;
	int len = sizeof(struct sockaddr_in6);
	char mybuff[256]; 
	if( argc != 3){
		printf("usage: <exe> <serverip> <port>\n");
		return -1;
	}
	
	mysock = socket(AF_INET6, SOCK_STREAM, 0);
	if(mysock < 0){
		printf("Error at socket().\n");
		return -1;
	}
	
	memset(&servaddr, 0, len);
	servaddr.sin6_family = AF_INET6;
	inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr);
	servaddr.sin6_port = htons(atoi(argv[2])); 

	if(connect(mysock,(struct sockaddr *) &servaddr, len) < 0){
		printf("connect error!\n");
		return -1;
	}
	memset(mybuff,0,sizeof(mybuff));			
 	printf("Client Send:");
 	gets(mybuff);
			
	bytes = send(mysock, mybuff, strlen(mybuff), 0);
	if( bytes>0 ){
		memset(mybuff,0,sizeof(mybuff));			
	}
	bytes = recv(mysock, mybuff, sizeof(mybuff), 0);
	if (bytes>0)
	{
		printf("client recv:%s\n", mybuff);
		memset(mybuff,0,sizeof(mybuff));			
	}
}</span>

 <img src="https://img-blog.csdn.net/20140614171203453?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMzg4OTc1Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />