zoukankan      html  css  js  c++  java
  • 基于TCP协议 I/O多路转接(select) 的高性能回显服务器客户端模型

    服务端代码:

    myselect.c

      1 #include <stdio.h>  
      2 #include <netinet/in.h>  
      3 #include <arpa/inet.h>  
      4 #include <sys/socket.h>  
      5 #include <sys/types.h>  
      6 #include <sys/stat.h>  
      7 #include <string.h>  
      8 #include <stdlib.h>  
      9 #include <unistd.h>  
     10   
     11   
     12 #define ARRAY_SIZE 1024  
     13   
     14   
     15 /* 使用说明 */  
     16 void usage(const char* proc)  
     17 {  
     18     printf("%s usage : [server_ip] [ server_port]
    ", proc);  
     19 }  
     20   
     21   
     22 /* 初始化一个socket连接 */  
     23 int init_sock(const char* _ip, int _port)  
     24 {  
     25     int sock = socket(AF_INET, SOCK_STREAM, 0);  
     26     if(sock < 0)  
     27     {  
     28         perror("socket");  
     29         exit(2);  
     30     }  
     31   
     32     int flg = 1;  
     33     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flg, sizeof(flg));  
     34     struct sockaddr_in local;  
     35     local.sin_family = AF_INET;  
     36     local.sin_port = htons(_port);  
     37     local.sin_addr.s_addr = inet_addr(_ip);  
     38   
     39     if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)  
     40     {  
     41         perror("bind");  
     42         exit(3);  
     43     }  
     44   
     45     if(listen(sock , 10) < 0)  
     46     {  
     47         perror("listen");  
     48         exit(4);  
     49     }  
     50   
     51     return sock;  
     52 }  
     53   
     54 /* 等待事件发生并处理 */  
     55 void run_select(int listen_sock)  
     56 {  
     57       
     58     int array_fds[ARRAY_SIZE];  /* 保存所有关心的描述符  */  
     59     array_fds[0] = listen_sock; /* 将listen_sock 保存*/  
     60   
     61     /* 初始化为 array_fds */  
     62     int idx_init = 1;  
     63     for(idx_init = 1; idx_init < ARRAY_SIZE; ++idx_init)  
     64         array_fds[idx_init] = -1;  
     65   
     66     fd_set rfds;      /* 关心的读事件描述符集 */  
     67     fd_set wfds;      /* 关心的写事件描述符集 */  
     68     int max_fd = -1;  
     69   
     70     struct timeval _timeout = {1, 0};  
     71   
     72     while(1)  
     73     {  
     74         max_fd = -1;  
     75         _timeout.tv_sec = 1;  
     76         FD_ZERO(&rfds);     
     77         FD_ZERO(&wfds);  
     78   
     79         /* 一. 将数组中存储的描述符,添加到关心的集合中  
     80          *  并找出其中最大的描述符, 
     81          */  
     82         int idx_add = 1;  
     83         for(idx_add = 0; idx_add < ARRAY_SIZE; idx_add++)  
     84         {  
     85             if(array_fds[idx_add] > 0)  
     86             {  
     87                 FD_SET(array_fds[idx_add], &rfds);  
     88                 FD_SET(array_fds[idx_add], &wfds);  
     89                 if(array_fds[idx_add] > max_fd)  
     90                     max_fd = array_fds[idx_add];  
     91   
     92             }  
     93         }  
     94         /* 二. 检测select的返回情况*/  
     95         int select_ret = select(max_fd+1, &rfds, &wfds, NULL, &_timeout);  
     96         switch( select_ret )  
     97         {  
     98             case 0:  
     99                 printf("timeout
    ");  
    100                 break;  
    101             case -1:  
    102                 perror("select
    ");  
    103                 break;  
    104             default:  
    105                 {  
    106                     /* 遍历数组,检测事件发生的描述符,并响应  */  
    107                     int idx_check = 0;  
    108                     for(idx_check = 0; idx_check < ARRAY_SIZE; ++idx_check)  
    109                     {  
    110                         if(array_fds[idx_check] < 0)  
    111                             continue;  
    112   
    113                         if(idx_check == 0 && FD_ISSET(array_fds[idx_check], &rfds) )  
    114                         { /* listensock 有数据来,表示有新的连接请求 */  
    115                             struct sockaddr_in client;  
    116                             socklen_t len = sizeof(client);  
    117   
    118                             int new_sock = accept(listen_sock, (struct sockaddr*)&client, &len);  
    119                             if(new_sock > 0)  
    120                             {  
    121                                 printf("新的连接请求来自: ip = %s, port = %d 
    ",inet_ntoa(client.sin_addr), ntohs(client.sin_port));  
    122   
    123                                 /* 在数组中找到未被占用的描述符位置,并保存新连接的描述符 */  
    124                                 int idx_find = 0;  
    125                                 for(idx_find = 1; idx_find < ARRAY_SIZE; ++idx_find)  
    126                                 {  
    127                                     if(array_fds[idx_find] < 0)  
    128                                     {  
    129                                         array_fds[idx_find] = new_sock;  
    130                                         break;  
    131                                     }  
    132                                 }  
    133                                 if(idx_find == ARRAY_SIZE)  
    134                                     close(new_sock);  
    135                             }  
    136                         } // << end if idx_check == 0 && FD_ISSET -- rfds>>   
    137                         else if( idx_check != 0 &&  FD_ISSET(array_fds[idx_check], &rfds) )  
    138                         { /* 其余描述符有数据来*/   
    139                               
    140                             char buf[ 1024];  
    141                             memset(buf, '', sizeof(buf));  
    142                             ssize_t s = read(array_fds[idx_check], buf, sizeof(buf) - 1);  
    143                             if(s > 0)  
    144                             {  
    145                                 printf("client say : %s
    ", buf);  
    146                                 if(FD_ISSET(array_fds[idx_check], &wfds))     
    147                                     write(array_fds[idx_check], buf, sizeof(buf)-1);  
    148                             }  
    149                             else if(s == 0)  
    150                             {  
    151                                 printf("client quit
    ");  
    152                                 close(array_fds[idx_check]);  
    153                                 array_fds[idx_check] = -1;  
    154                             }  
    155                             else  
    156                             {  
    157                                 perror("read fail");  
    158                                 close(array_fds[idx_check]);  
    159                                 array_fds[idx_check] = -1;  
    160                             }  
    161                         } // << end else if idx_check != 0 && FD_ISSET -- rfds >>  
    162                     } // << end for idx_check = 0; idx_check<ARRAY_SIZE; ++idx_check >>  
    163                 } // << end default >>  
    164                 break;  
    165         } // << end switch select >>  
    166     } // << end while 1 >>  
    167 }  
    168   
    169 int main(int argc, char **argv)  
    170 {  
    171     if(3 != argc)  
    172     {  
    173         usage(argv[0]);  
    174         exit(1);  
    175     }  
    176   
    177     int sock = init_sock(argv[1], atoi(argv[2]));  
    178   
    179     printf("start run_select
    ");  
    180     run_select(sock);  
    181   
    182     return 0;  
    183 }     

    客户端代码:

    为了练习dup 和 dup2 函数的使用,在客户端中,使用了这两个函数进行标准输出的重定向以及恢复,使用printf 函数向sockfd 中写数据,并提示用户输入。

     1 #include <stdio.h>  
     2 #include <unistd.h>  
     3 #include <string.h>  
     4 #include <fcntl.h>  
     5 #include <sys/types.h>  
     6 #include <sys/stat.h>  
     7 #include <netinet/in.h>  
     8 #include <sys/socket.h>  
     9 #include <arpa/inet.h>  
    10 #include <stdlib.h>  
    11   
    12 int main(int argc, char **argv)  
    13 {  
    14     if(argc != 3)  
    15     {  
    16         printf("Usage [server_ip] [ server_port]
    ");  
    17         exit(1);  
    18     }  
    19   
    20     int sock = socket(AF_INET, SOCK_STREAM, 0);  
    21     if(sock < 0)  
    22     {  
    23         perror("socket");  
    24         exit(2);  
    25     }  
    26   
    27     struct sockaddr_in server;  
    28     server.sin_family = AF_INET;  
    29     server.sin_addr.s_addr = inet_addr(argv[1]);  
    30     server.sin_port = htons(atoi(argv[2]));  
    31   
    32   
    33   
    34     if(connect(sock,(struct sockaddr*)&server, sizeof(server))<0)  
    35     {  
    36         perror("connect");  
    37         exit(3);  
    38     }  
    39   
    40     // 保存标准输出的描述符  
    41     int oldfd = dup(STDOUT_FILENO);  
    42     char buf[1024];  
    43   
    44     while(1)  
    45     {  
    46         printf("please input #");  
    47         fflush(stdout);  
    48         memset(buf, '', sizeof(buf));  
    49   
    50         /* 重定向输出到sock */  
    51         dup2(sock, STDOUT_FILENO);  
    52         ssize_t s = read(0, buf, sizeof(buf)-1);  
    53         if(s > 0)  
    54         {  
    55             /* 处理客户端只输入一个回车而程序挂起的bug */  
    56             if( buf[0] == '
    ' )  
    57             {  
    58                 dup2(oldfd, STDOUT_FILENO);  
    59                 continue;  
    60             }  
    61   
    62             if(strncmp("quit", buf, 4) == 0)  
    63                 break;  
    64   
    65             buf[s - 1] = 0;  
    66   
    67             /* 用printf 向sock写 */  
    68             printf("%s", buf);  
    69             fflush(stdout);  
    70   
    71             /* 恢复 标准输出 */  
    72             dup2(oldfd, STDOUT_FILENO);  
    73   
    74             /* 从sock读服务端回显的数据,  */  
    75             ssize_t _s =  read(sock, buf, sizeof(buf) - 1);  
    76             if(_s >0)  
    77             {  
    78                 buf[_s] = 0;  
    79                 printf("server echo # %s
    ", buf);  
    80             }  
    81             else if (s <= 0)  
    82             {  
    83                 continue;  
    84             }  
    85         }  
    86     }  
    87   
    88     close(sock);  
    89     close(oldfd);  
    90   
    91     return 0;  
    92 }  
  • 相关阅读:
    openjudge666:放苹果—题解
    欢迎来到路由器的世界!这里是开端
    Codevs1169:传纸条——题解
    POJ3498:March of the Penguins——题解
    模板:并查集
    模板:快速幂
    模板:排序(三)
    程序员之间的鄙视链
    自动化测试的成本高效果差,那么自动化测试的意义在哪呢
    自动化测试的成本高效果差,那么自动化测试的意义在哪呢
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/8831112.html
Copyright © 2011-2022 走看看