• 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去连接,然后观察服务端的输出,有助于理解底层的交互过程。

     
     
  • 相关阅读:
    mysql 查询技巧
    如何查看mysql索引
    windows下安装redis以及简单的事例
    Buildroot make网卡interfaces文件被修改
    VirtualBox只能生成32位虚拟机
    python-websocket-server hacking
    crontab定时任务
    Linux修改串口irq
    emmc boot_config文件不存在
    /dev/mem直接操作硬件寄存器
  • 原文地址:https://www.cnblogs.com/Pond-ZZC/p/7600416.html
Copyright © 2020-2023  润新知