C++ IPv4与IPv6的兼容编码(转,出自http://blog.csdn.net/ligt0610/article/details/18667595)

这里不再对IPv6 socket相关编程的基础知识进行讲解,只提供一个IP协议无关的服务端和客户端的代码,仅供参考。

服务端代码:

[cpp] view plain copy
 
  1. #include <iostream>  
  2. #include <string>  
  3. #include <sys/types.h>  
  4. #include <sys/socket.h>  
  5. #include <arpa/inet.h>  
  6. #include <netdb.h>  
  7. #include <errno.h>  
  8. #include <time.h>  
  9.   
  10. using namespace std;  
  11.   
  12. int tcp_listen(const char *host, const char *service, const int listen_num = 5)  
  13. {  
  14.     int listenfd, ret;  
  15.     const int on = 1;  
  16.     struct addrinfo hints, *res, *ressave;  
  17.     bzero(&hints, sizeof(hints));  
  18.     hints.ai_flags = AI_PASSIVE;  
  19.     hints.ai_family = AF_UNSPEC;  
  20.     hints.ai_socktype = SOCK_STREAM;  
  21.     hints.ai_protocol = IPPROTO_IP;  
  22.   
  23.     if (0 != (ret = getaddrinfo(host, service, &hints, &res)))  
  24.     {  
  25.         cout << "getaddrinfo error: " << gai_strerror(ret) << endl;  
  26.         return -1;  
  27.     }  
  28.   
  29.     ressave = res;  
  30.     while(NULL != res)  
  31.     {  
  32.         if (-1 == (listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)))  
  33.         {  
  34.             cout << "create socket error: " << strerror(errno) << endl;  
  35.             res = res->ai_next;  
  36.             continue;  
  37.         }  
  38.   
  39.         if (-1 == setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))  
  40.         {  
  41.             cout << "setsockopt error: " << strerror(errno) << endl;  
  42.             close(listenfd);  
  43.             res = res->ai_next;  
  44.             continue;  
  45.         }  
  46.   
  47.         if (-1 == bind(listenfd, res->ai_addr, res->ai_addrlen))  
  48.         {  
  49.             cout << "bind error: " << strerror(errno) << endl;  
  50.                         close(listenfd);  
  51.                         res = res->ai_next;  
  52.                         continue;  
  53.         }  
  54.   
  55.         if (-1 == listen(listenfd, listen_num))  
  56.         {  
  57.             cout << "listen error: " << strerror(errno) << endl;  
  58.                         close(listenfd);  
  59.                         res = res->ai_next;  
  60.                         continue;  
  61.         }  
  62.   
  63.         break;  
  64.     }  
  65.   
  66.     freeaddrinfo(ressave);  
  67.   
  68.     if (NULL == res)  
  69.         return -1;  
  70.   
  71.     return listenfd;  
  72. }  
  73.   
  74. int get_addrinfo(const struct sockaddr *addr, string &ip, in_port_t &port)  
  75. {  
  76.     void *numeric_addr = NULL;  
  77.     char addr_buff[INET6_ADDRSTRLEN];  
  78.   
  79.     if (AF_INET == addr->sa_family)  
  80.     {  
  81.         numeric_addr = &((struct sockaddr_in*)addr)->sin_addr;  
  82.         port = ntohs(((struct sockaddr_in*)addr)->sin_port);  
  83.     }  
  84.     else if (AF_INET6 == addr->sa_family)  
  85.     {  
  86.         numeric_addr = &((struct sockaddr_in6*)addr)->sin6_addr;  
  87.         port = ntohs(((struct sockaddr_in6*)addr)->sin6_port);  
  88.     }  
  89.     else  
  90.     {  
  91.         return -1;  
  92.     }  
  93.   
  94.     if (NULL != inet_ntop(addr->sa_family, numeric_addr, addr_buff, sizeof(addr_buff)))  
  95.         ip = addr_buff;  
  96.     else  
  97.         return -1;  
  98.   
  99.     return 0;  
  100. }  
  101.   
  102. int main(int argc, char *argv[])  
  103. {  
  104.     int listenfd, connfd;  
  105.     struct sockaddr_storage cliaddr;  
  106.     socklen_t len = sizeof(cliaddr);  
  107.     time_t now;  
  108.     char buff[128];  
  109.   
  110.     if (2 == argc) //指定端口  
  111.         listenfd = tcp_listen(NULL, argv[1]);  
  112.     else if (3 == argc) //指定本地IP和端口  
  113.         listenfd = tcp_listen(argv[1], argv[2]);  
  114.     else  
  115.     {  
  116.                 cout << "usage: " << argv[0] << " [<hostname/ipaddress>] <service/port>" << endl;  
  117.         return -1;  
  118.     }  
  119.   
  120.     if (listenfd < 0)  
  121.     {  
  122.         cout << "call tcp_listen error" << endl;  
  123.         return -1;  
  124.     }  
  125.   
  126.     while (true)  
  127.     {  
  128.         connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &len);  
  129.   
  130.         string ip = "";  
  131.         in_port_t port = 0;  
  132.         get_addrinfo((struct sockaddr*)&cliaddr, ip, port);  
  133.         cout << "client " << ip << "|" << port << " login" << endl;  
  134.   
  135.         now = time(NULL);  
  136.         snprintf(buff, sizeof(buff) - 1, "%.24s", ctime(&now));  
  137.         write(connfd, buff, strlen(buff));  
  138.         close(connfd);  
  139.     }  
  140.   
  141.     close(listenfd);  
  142.     return 0;  
  143. }  
客户端代码:
[cpp] view plain copy
 
  1. #include <iostream>  
  2. #include <string>  
  3. #include <sys/types.h>  
  4. #include <sys/socket.h>  
  5. #include <arpa/inet.h>  
  6. #include <netdb.h>  
  7. #include <errno.h>  
  8. #include <time.h>  
  9.   
  10. using namespace std;  
  11.   
  12. int tcp_connect(const char *host, const char *service)  
  13. {  
  14.     int sockfd, ret;  
  15.     struct addrinfo hints, *res, *ressave;  
  16.     bzero(&hints, sizeof(hints));  
  17.     hints.ai_family = AF_UNSPEC;  
  18.     hints.ai_socktype = SOCK_STREAM;  
  19.     hints.ai_protocol = IPPROTO_IP;  
  20.   
  21.     if (0 != (ret = getaddrinfo(host, service, &hints, &res)))  
  22.     {  
  23.         cout << "getaddrinfo error: " << gai_strerror(ret) << endl;  
  24.         return -1;  
  25.     }  
  26.   
  27.     ressave = res;  
  28.     while (NULL != res)  
  29.     {  
  30.         if (-1 == (sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)))  
  31.                 {  
  32.                         cout << "create socket error: " << strerror(errno) << endl;  
  33.                         res = res->ai_next;  
  34.                         continue;  
  35.                 }  
  36.   
  37.         if (-1 == connect(sockfd, res->ai_addr, res->ai_addrlen))  
  38.         {  
  39.             cout << "connect error: " << strerror(errno) << endl;  
  40.                         close(sockfd);  
  41.             res = res->ai_next;  
  42.                         continue;  
  43.         }  
  44.   
  45.         break;  
  46.     }  
  47.       
  48.     freeaddrinfo(ressave);  
  49.   
  50.     if (NULL == res)  
  51.         return -1;  
  52.   
  53.     return sockfd;  
  54. }  
  55.   
  56. int main(int argc, char *argv[])  
  57. {  
  58.     int sockfd, n;  
  59.     char buff[128];  
  60.     struct sockaddr_storage cliaddr;  
  61.       
  62.     if (3 != argc)  
  63.     {  
  64.         cout << "usage: " << argv[0] << " <hostname/ipaddress> <service/port>" << endl;  
  65.         return -1;  
  66.     }  
  67.   
  68.     sockfd = tcp_connect(argv[1], argv[2]);  
  69.     if (sockfd < 0)  
  70.     {  
  71.         cout << "call tcp_connect error" << endl;  
  72.         return -1;  
  73.     }  
  74.   
  75.     bzero(buff, sizeof(buff));  
  76.     while ((n = read(sockfd, buff, sizeof(buff) - 1) > 0))  
  77.     {  
  78.         cout << buff << endl;  
  79.         bzero(buff, sizeof(buff));  
  80.     }  
  81.     close(sockfd);  
  82.   
  83.     return 0;  
  84. }  


编译:

g++ daytimesrv.cpp -o daytimesrv

g++ daytimecli.cpp -o daytimecli

运行举例:

服务端运行情况:

客户端运行情况:

以上客户端的请求与服务端的输出一一对应,客户端可以尝试用不同的IP去连接,然后观察服务端的输出,有助于理解底层的交互过程。

 
 
原文地址:https://www.cnblogs.com/Pond-ZZC/p/7600416.html