一、TCP socket ipv6与ipv4的区别

服务器端源代码如下:

  1 #include <stdio.h>  
  2 #include <stdlib.h>  
  3 #include <errno.h>  
  4 #include <string.h>  
  5 #include <sys/types.h>  
  6 #include <netinet/in.h>  
  7 #include <sys/socket.h>  
  8 #include <sys/wait.h>  
  9 #include <unistd.h>  
 10 #include <arpa/inet.h>  
 11 #define MAXBUF 1024  
 12 int main(int argc, char **argv)  
 13 {  
 14     int sockfd, new_fd;  
 15     socklen_t len;  
 16   
 17     /* struct sockaddr_in my_addr, their_addr; */ // IPv4  
 18     struct sockaddr_in6 my_addr, their_addr; // IPv6  
 19   
 20     unsigned int myport, lisnum;  
 21     char buf[MAXBUF + 1];  
 22   
 23     if (argv[1])  
 24         myport = atoi(argv[1]);  
 25     else  
 26         myport = 7838;  
 27   
 28     if (argv[2])  
 29         lisnum = atoi(argv[2]);  
 30     else  
 31         lisnum = 2;  
 32   
 33     /* if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { */ // IPv4  
 34     if ((sockfd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { // IPv6  
 35         perror("socket");  
 36         exit(1);  
 37     } else  
 38         printf("socket created/n");  
 39   
 40     bzero(&my_addr, sizeof(my_addr));  
 41     /* my_addr.sin_family = PF_INET; */ // IPv4  
 42     my_addr.sin6_family = PF_INET6;    // IPv6  
 43     /* my_addr.sin_port = htons(myport); */ // IPv4  
 44     my_addr.sin6_port = htons(myport);   // IPv6  
 45     if (argv[3])  
 46         /* my_addr.sin_addr.s_addr = inet_addr(argv[3]); */ // IPv4  
 47         inet_pton(AF_INET6, argv[3], &my_addr.sin6_addr);  // IPv6  
 48     else  
 49         /* my_addr.sin_addr.s_addr = INADDR_ANY; */ // IPv4  
 50         my_addr.sin6_addr = in6addr_any;            // IPv6  
 51   
 52     /* if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) */ // IPv4  
 53     if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in6))  // IPv6  
 54         == -1) {  
 55         perror("bind");  
 56         exit(1);  
 57     } else  
 58         printf("binded/n");  
 59   
 60     if (listen(sockfd, lisnum) == -1) {  
 61         perror("listen");  
 62         exit(1);  
 63     } else  
 64         printf("begin listen/n");  
 65   
 66     while (1) {  
 67         len = sizeof(struct sockaddr);  
 68         if ((new_fd =  
 69              accept(sockfd, (struct sockaddr *) &their_addr,  
 70                     &len)) == -1) {  
 71             perror("accept");  
 72             exit(errno);  
 73         } else  
 74             printf("server: got connection from %s, port %d, socket %d/n",  
 75                    /* inet_ntoa(their_addr.sin_addr), */ // IPv4  
 76                    inet_ntop(AF_INET6, &their_addr.sin6_addr, buf, sizeof(buf)), // IPv6  
 77                    /* ntohs(their_addr.sin_port), new_fd); */ // IPv4  
 78                    their_addr.sin6_port, new_fd); // IPv6  
 79   
 80         /* 开始处理每个新连接上的数据收发 */  
 81         bzero(buf, MAXBUF + 1);  
 82         strcpy(buf,  
 83                "这是在连接建立成功后向客户端发送的第一个消息/n只能向new_fd这个用accept函数新建立的socket发消息,不能向sockfd这个监听socket发送消息,监听socket不能用来接收或发送消息/n");  
 84         /* 发消息给客户端 */  
 85         len = send(new_fd, buf, strlen(buf), 0);  
 86         if (len < 0) {  
 87             printf  
 88                 ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n",  
 89                  buf, errno, strerror(errno));  
 90         } else  
 91             printf("消息'%s'发送成功,共发送了%d个字节!/n",  
 92                    buf, len);  
 93   
 94         bzero(buf, MAXBUF + 1);  
 95         /* 接收客户端的消息 */  
 96         len = recv(new_fd, buf, MAXBUF, 0);  
 97         if (len > 0)  
 98             printf("接收消息成功:'%s',共%d个字节的数据/n",  
 99                    buf, len);  
100         else  
101             printf  
102                 ("消息接收失败!错误代码是%d,错误信息是'%s'/n",  
103                  errno, strerror(errno));  
104         /* 处理每个新连接上的数据收发结束 */  
105     }  
106   
107     close(sockfd);  
108     return 0;  
109 }   

 

每行程序后面的 “//IPv4” 表示这行代码是在IPv4网络里用的

而“//IPv6” 表示这行代码是在IPv6网络里用的,比较一下,会很容易看到差别的。
客户端源代码如下:

 1 #include <stdio.h>  
 2 #include <string.h>  
 3 #include <errno.h>  
 4 #include <sys/socket.h>  
 5 #include <resolv.h>  
 6 #include <stdlib.h>  
 7 #include <netinet/in.h>  
 8 #include <arpa/inet.h>  
 9 #include <unistd.h>  
10 #define MAXBUF 1024  
11 int main(int argc, char **argv)  
12 {  
13     int sockfd, len;  
14     /* struct sockaddr_in dest; */ // IPv4  
15     struct sockaddr_in6 dest;      // IPv6  
16     char buffer[MAXBUF + 1];  
17   
18     if (argc != 3) {  
19         printf  
20             ("参数格式错误!正确用法如下:/n/t/t%s IP地址 端口/n/t比如:/t%s 127.0.0.1 80/n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",  
21              argv[0], argv[0]);  
22         exit(0);  
23     }  
24     /* 创建一个 socket 用于 tcp 通信 */  
25     /* if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { */ // IPv4  
26     if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {      // IPv6  
27         perror("Socket");  
28         exit(errno);  
29     }  
30     printf("socket created/n");  
31   
32     /* 初始化服务器端(对方)的地址和端口信息 */  
33     bzero(&dest, sizeof(dest));  
34     /* dest.sin_family = AF_INET; */  // IPv4  
35     dest.sin6_family = AF_INET6;     // IPv6  
36     /* dest.sin_port = htons(atoi(argv[2])); */ // IPv4  
37     dest.sin6_port = htons(atoi(argv[2]));     // IPv6  
38     /* if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { */ // IPv4  
39     if ( inet_pton(AF_INET6, argv[1], &dest.sin6_addr) < 0 ) {                 // IPv6  
40         perror(argv[1]);  
41         exit(errno);  
42     }  
43     printf("address created/n");  
44   
45     /* 连接服务器 */  
46     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {  
47         perror("Connect ");  
48         exit(errno);  
49     }  
50     printf("server connected/n");  
51   
52     /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */  
53     bzero(buffer, MAXBUF + 1);  
54     /* 接收服务器来的消息 */  
55     len = recv(sockfd, buffer, MAXBUF, 0);  
56     if (len > 0)  
57         printf("接收消息成功:'%s',共%d个字节的数据/n",  
58                buffer, len);  
59     else  
60         printf  
61             ("消息接收失败!错误代码是%d,错误信息是'%s'/n",  
62              errno, strerror(errno));  
63   
64     bzero(buffer, MAXBUF + 1);  
65     strcpy(buffer, "这是客户端发给服务器端的消息/n");  
66     /* 发消息给服务器 */  
67     len = send(sockfd, buffer, strlen(buffer), 0);  
68     if (len < 0)  
69         printf  
70             ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n",  
71              buffer, errno, strerror(errno));  
72     else  
73         printf("消息'%s'发送成功,共发送了%d个字节!/n",  
74                buffer, len);  
75   
76     /* 关闭连接 */  
77     close(sockfd);  
78     return 0;  
79 }  

 

编译程序用下列命令:
gcc -Wall ipv6-server.c -o ipv6server
gcc -Wall ipv6-client.c -o ipv6client
你自己的主机有IPv6地址吗?很多人会问,输入ifconfig命令看一下吧:

eth0      链路封装:以太网  硬件地址 00:14:2A:6D:5B:A5  
          inet 地址:192.168.0.167  广播:192.168.0.255  掩码:255.255.255.0
          inet6 地址: fe80::214:2aff:fe6d:5ba5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1
          接收数据包:30507 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:26797 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:31461154 (30.0 MiB)  发送字节:4472810 (4.2 MiB)
          中断:185 基本地址:0xe400 

lo        链路封装:本地环回  
          inet 地址:127.0.0.1  掩码:255.0.0.0
          inet6 地址: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  跃点数:1
          接收数据包:13 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:13 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:0 
          接收字节:1178 (1.1 KiB)  发送字节:1178 (1.1 KiB)

  
看到“inet6 地址:”这两行了吗?后面就是你的IPv6地址
启动服务:
./ipv6server 7838 1
或者加上IP地址启动服务:
./ipv6server 7838 1 fe80::214:2aff:fe6d:5ba5
启动客户端测试一下:
./ipv6client ::1/128 7838 

./ipv6client fe80::214:2aff:fe6d:5ba5 7838

二、UDP ipv6例子

UDP服务端:

 1 #include <unistd.h>  
 2 #include <stdio.h>  
 3 #include <arpa/inet.h>  
 4 #include <sys/socket.h>  
 5 #include <string.h>  
 6 #define LOCALPORT 8888  
 7 int main(int argc,char *argv[])  
 8 {  
 9     int mysocket,len;  
10     int i=0;  
11     struct sockaddr_in6 addr;  
12     int addr_len;  
13     char msg[200];  
14     char buf[300];  
15   
16     if((mysocket=socket(AF_INET6,SOCK_DGRAM,0))<0)  
17     {  
18         perror("error:");  
19         return(1);  
20     }  
21     else  
22     {  
23         printf("socket created ...\n");  
24         printf("socket id :%d \n",mysocket);  
25     }  
26   
27     addr_len=sizeof(struct sockaddr_in6);  
28     bzero(&addr,sizeof(addr));  
29     addr.sin6_family=AF_INET6;  
30     addr.sin6_port=htons(LOCALPORT);  
31     addr.sin6_addr=in6addr_any;  
32   
33     if(bind(mysocket,(struct sockaddr *)&addr,sizeof(addr))<0)  
34     {  
35         perror("connect");  
36         return(1);  
37     }  
38     else  
39     {  
40         printf("bink ok .\n");  
41         printf("local port : %d\n",LOCALPORT);  
42     }  
43     while(1)  
44     {  
45         bzero(msg,sizeof(msg));  
46         len = recvfrom(mysocket,msg,sizeof(msg),0,(struct sockaddr *)&addr,(socklen_t*)&addr_len);  
47         printf("%d:",i);  
48         i++;  
49         inet_ntop(AF_INET6,&addr.sin6_addr,buf,sizeof(buf));  
50         printf("message from ip %s",buf);  
51         printf("Received message : %s\n",msg);  
52         if(sendto(mysocket,msg,len,0,(struct sockaddr *)&addr,addr_len)<0)  
53         {  
54             printf("error");  
55             return(1);  
56         }  
57     }  
58 }  

 

   
 UDP客户端代码:

 1 #include <stdio.h>  
 2 #include <arpa/inet.h>  
 3 #include <unistd.h>  
 4 #include <sys/socket.h>  
 5 #include <string.h>  
 6 #define REMOTEPORT 8888  
 7 #define REMOTEIP "::1"  
 8 int main(int argc,char *argv[])  
 9 {  
10     int mysocket,len;  
11     int i=0;  
12     struct sockaddr_in6 addr;  
13     int addr_len;  
14     char msg[200];  
15     if((mysocket=socket(AF_INET6,SOCK_DGRAM,0))<0)  
16     {  
17         perror("error:");  
18         return(1);  
19     }  
20     else  
21     {  
22         printf("socket created ...\n");  
23         printf("socket id :%d \n",mysocket);  
24         printf("rmote ip : %s\n",REMOTEIP);  
25         printf("remote port :%d \n",REMOTEPORT);  
26     }  
27   
28     addr_len=sizeof(struct sockaddr_in6);  
29     bzero(&addr,sizeof(addr));  
30     addr.sin6_family=AF_INET6;  
31     addr.sin6_port=htons(REMOTEPORT);  
32     inet_pton(AF_INET6,REMOTEIP,&addr.sin6_addr);  
33   
34     while(1)  
35     {  
36         bzero(msg,sizeof(msg));  
37         len=read(STDIN_FILENO,msg,sizeof(msg));  
38         if(sendto(mysocket,msg,sizeof(msg),0,(struct sockaddr *)&addr,addr_len)<0)  
39         {  
40             printf("error");  
41             return(1);  
42         }  
43         len=recvfrom(mysocket,msg,sizeof(msg),0,(struct sockaddr *)&addr,(socklen_t*)&addr_len);  
44         printf("%d:",i);  
45         i++;  
46         printf("Received message : %s\n",msg);  
47     }  
48 }  
49  

 

 "::1"相当于ipv4下的lo,即127网段


三、ipv6环境下inet_pton和inet_ntop

附上一段ipv6环境下inet_pton和inet_ntop函数代码

 

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3 #include <string.h>  
 4 #include <arpa/inet.h>  
 5   
 6 int main(int argc, char **argv)  
 7 {  
 8     unsigned char buf[sizeof(struct in6_addr)];  
 9     int domain, s;  
10     char str[INET6_ADDRSTRLEN];  
11   
12     if(argc != 3){  
13         fprintf(stderr, "usage: %s {i4|i6|<num>} string\n", argv[0]);  
14         exit(EXIT_FAILURE);  
15     }  
16   
17     domain = (strcmp(argv[1], "i4") == 0) ? AF_INET:(strcmp(argv[1], "i6") == 0) ? AF_INET6 : atoi(argv[1]);  
18       
19     //IP字符串 ——》网络字节流  
20     s = inet_pton(domain, argv[2], buf);  
21     if(s<=0)  
22     {  
23         if(0 == s)  
24             fprintf(stderr, "Not in presentation format\n");  
25         else  
26             perror("inet_pton");  
27         exit(EXIT_FAILURE);  
28     }  
29   
30     //网络字节流 ——》IP字符串  
31     if(inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == NULL){    
32         perror("inet ntop\n");  
33         exit(EXIT_FAILURE);  
34     }  
35     printf("%s\n", str);  
36     exit(EXIT_SUCCESS);  
37 }  
38  

 


四、兼容IPV4和IPV6地址代码

为了能够兼容ipv4和ipv6,可以组织代码如下:

 1 #define ADDRESS_BUFFER 50  
 2   
 3 typedef class address  
 4 {  
 5 private:  
 6     short int sin_family; //address family AF_INET or AF_INET6  
 7     union  
 8     {     
 9         char binary_addr4[IPV4_LEN];  
10         char binary_addr6[IPV6_LEN];  
11     }addr;  
12     char readable_addr[ADDRESS_BUFFER];  
13   
14 public:  
15     address();  
16     bool operator == (const address &dst) const;  
17     bool operator != (const address &dst) const { return (*this == dst? false : true );}   
18     bool operator < (const address &dst) const;  
19     const char* get_readable_address() const {return readable_addr;}  
20     int get_family() const {return sin_family;}  
21     bool is_ipv6() const {return sin_family == AF_INET6;}  
22     void set_family(int af) {if(af != AF_INET && af != AF_INET6) return; sin_family = af;}  
23     bool set_from_readable_address(const char* readable_address);  
24     const char* get_binary_data() {return (char*)&addr;}  
25 }address;  


这里最重要的函数是set_from_readable_address函数,该函数是整个类的入口,执行该函数需要传入一个可读的IP地址,ipv4应该是"xxx.xxx.xxx.xxx"形式,ipv6应该是如:“ff01::1”或者"ffec:afaf::111"等可读的格式,返回false代表转换格式遇到错误,下面贴上该函数的实现代码,其它函数有兴趣的可以自己实现

 1 bool address::set_from_readable_address(const char* readable_address)  
 2 {  
 3     if(readable_address == NULL)  
 4         return false;  
 5     memset(addr.binary_addr6, 0, sizeof(addr.binary_addr6));  
 6     const char*p = readable_address;  
 7     int cnt = 0;  
 8     for(; *p != '\0';p++)  
 9         if(*p == ':')  
10             cnt++;  
11     if(cnt >= 2)  
12     {  
13         sin_family = AF_INET6;  
14         if( inet_pton(PF_INET6,readable_address,addr.binary_addr6) <= 0)  
15             return false;  
16         strncpy(readable_addr, readable_address, ADDRESS_BUFFER);  
17     }else  
18     {  
19         sin_family = AF_INET;  
20         if( inet_pton(PF_INET,readable_address,addr.binary_addr4) <= 0)  
21             return false;  
22         strncpy(readable_addr, readable_address, ADDRESS_BUFFER);  
23     }  
24     return true;  
25 }  

 

posted on 2016-05-30 10:37  千叶大人  阅读(21713)  评论(0编辑  收藏  举报