zoukankan      html  css  js  c++  java
  • IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类

     一、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 }  
  • 相关阅读:
    vim内外部鼠标复制 粘贴
    nginx 问题解决nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    Installation of the latest version of netease-cloud-music on Fedora 30 linux platform
    Linux就该这么学11学习笔记
    Linux就该这么学10学习笔记
    css day2
    Linux就该这么学09学习笔记
    Linux就该这么学08学习笔记
    css day1
    Linux就该这么学07学习笔记
  • 原文地址:https://www.cnblogs.com/wuyuxuan/p/5541598.html
Copyright © 2011-2022 走看看