一、TCP socket ipv6与ipv4的区别
    服务器端源代码如下:
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图1
    1 #include
    2 #include
    3 #include
    4 #include
    5 #include
    6 #include
    7 #include
    8 #include
    9 #include
    10 #include
    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 }
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图2

    每行程序后面的 “//IPv4” 表示这行代码是在IPv4网络里用的
    而“//IPv6” 表示这行代码是在IPv6网络里用的,比较一下,会很容易看到差别的。
    客户端源代码如下:
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图3
    1 #include
    2 #include
    3 #include
    4 #include
    5 #include
    6 #include
    7 #include
    8 #include
    9 #include
    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 }
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图4

    编译程序用下列命令:
    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服务端:
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图5
    1 #include
    2 #include
    3 #include
    4 #include
    5 #include
    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 }
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图6


    UDP客户端代码:
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图7
    1 #include
    2 #include
    3 #include
    4 #include
    5 #include
    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
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图8

    “::1”相当于ipv4下的lo,即127网段
    三、ipv6环境下inet_pton和inet_ntop
    附上一段ipv6环境下inet_pton和inet_ntop函数代码

    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图9
    1 #include
    2 #include
    3 #include
    4 #include
    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|} 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
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图10

    四、兼容IPV4和IPV6地址代码
    为了能够兼容ipv4和ipv6,可以组织代码如下:
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图11
    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;
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图12
    这里最重要的函数是set_from_readable_address函数,该函数是整个类的入口,执行该函数需要传入一个可读的IP地址,ipv4应该是”xxx.xxx.xxx.xxx”形式,ipv6应该是如:“ff01::1”或者”ffec:afaf::111”等可读的格式,返回false代表转换格式遇到错误,下面贴上该函数的实现代码,其它函数有兴趣的可以自己实现
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图13
    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 }
    IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类 - 图14