zoukankan      html  css  js  c++  java
  • io复用select方法编写的服务器

    • 摘要:io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作。select函数作为io多路复用的机制,第一个参数nfds是fd_set集合中最大描述符值+1,fdset是一个位数组,每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误时间的文件描述符位数组,这些参数既是输入型参数也是输出型参数,可能会被内核修改用于标识哪些描述符上发生了关注的事件,所以每次调用select前都需要重新
    • io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作。select函数作为io多路复用的机制,第一个参数nfds是fd_set集合中最大描述符值+1,fdset是一个位数组,每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误时间的文件描述符位数组,这些参数既是输入型参数也是输出型参数,可能会被内核修改用于标识哪些描述符上发生了关注的事件,所以每次调用select前都需要重新初始化fdset。timeout参数为超时时间,该结构会被内核修改,其值为超时剩余时间。

      select函数返回值有三种,返回-1时表示select失败;返回0表示超时;其他返回值表示select成功。

    •  2018-12-02 18:56:42

      1 #include<stdio.h>
      2 #include<sys/socket.h>
      3 #include<sys/types.h>
      4 #include<stdlib.h>
      5 #include<netinet/in.h>
      6 #include<arpa/inet.h>
      7 #include<assert.h>
      8 int rfds[128];
      9 void usage(const char* proc)
     10 {
     11     assert(proc);
     12     printf("usage:%s: [ip] [port]/n",proc);
     13 }
     14 int start_up(const char* ip,int port)
     15 { 
     16     assert(ip);
     17     assert(port > 0);
     18     int sock = socket(AF_INET,SOCK_STREAM,0); 
     19     if(sock < 0) 
     20     { 
     21         perror("socket");
     22         exit(2); 
     23     } 
     24     struct sockaddr_in local; 
     25     local.sin_family = AF_INET; 
     26     local.sin_port = htons(port); 
     27     local.sin_addr.s_addr =inet_addr(ip);
     28     if(bind(sock,(struct sockaddr*)&;local,sizeof(local)) < 0)
     29     { 
     30         perror("bind");
     31         exit(3); 
     32     }
     33  
     34     if(listen(sock,5) < 0) 
     35     {
     36         perror("listen"); 
     37         exit(4); 
     38     } 
     39     return sock;
     40     }
     41 int main(int argc,char* argv[])
     42 { 
     43     if(argc != 3) 
     44     { 
     45         usage(argv[0]);
     46         return 1;
     47     } 
     48     int listen_sock = start_up(argv[1],atoi(argv[2]));
     49     for(int i=0 ;i < 128; i++) 
     50     {
     51         rfds[i] = -1;
     52     } 
     53     fd_set rset; 
     54     int max_fd = 0; 
     55     while(1) 
     56     {
     57         struct timeval timeout = {0,0};
     58         FD_ZERO(&;rset);
     59         rfds[0] = listen_sock;
     60         max_fd = listen_sock; 
     61         for(int i=0 ;i < 128; i++) 
     62         { 
     63             if(rfds[i] >= 0) 
     64             {
     65                 FD_SET(rfds[i],&;rset);
     66                 if(max_fd < rfds[i]) 
     67                     max_fd = rfds[i]; 
     68             } 
     69         }
     70         switch(select(max_fd + 1,&;rset,NULL,NULL,NULL))
     71         { 
     72         case -1: 
     73                 perror("select");
     74                 break; 
     75         case 0: 
     76                 printf("timeout");
     77                 break;            
     78         default: 
     79         { 
     80             int j = 0;
     81             for(;j < 128;j++) 
     82             { 
     83                 if(rfds[j] < 0)
     84                     continue; 
     85                 if(j == 0&;&;FD_ISSET(rfds[j],&;rset))
     86                 { 
     87                     struct sockaddr_in client; 
     88                     socklen_t len = sizeof(client); 
     89                     int new_fd = accept(listen_sock,(struct sockaddr*)&;client,&;len); 
     90                     if(new_fd < 0) 
     91                     {
     92                         perror("accept");
     93                     } 
     94                     else 
     95                     { 
     96                         printf("get a client:socket :%s:%d/n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
     97                         int k = 0; 
     98                         for(;k < 128;k++)
     99                         { 
    100                             if(rfds[k] == -1) 
    101                             { 
    102                                 rfds[k] = new_fd; break;
    103                             } 
    104                         } 
    105                         if( k == 128)
    106                         {
    107                             close(new_fd); 
    108                         } 
    109                     } 
    110                 } 
    111                 else if(FD_ISSET(rfds[j],&;rset)) 
    112                 { 
    113                     char buf[1024]; 
    114                     ssize_t s = read(rfds[j],buf,sizeof(buf)-1);
    115                     if(s > 0)
    116                     {
    117                         buf[s] = 0;
    118                         printf("client#%s/n",buf);
    119                     }
    120                     else if(s == 0) 
    121                     { 
    122                         printf("client close.../n");
    123                         close(rfds[j]); rfds[j] = -1; 
    124                     } 
    125                     else 
    126                     { 
    127                         perror("read"); 
    128                     } 
    129                 } 
    130             }
    131         } 
    132         break;
    133         }
    134     }
    135 }
    select_server.c

    使用telnet为一个客户端访问:

    使用select编写服务器

    当把服务器终止后,再次打开服务器会出现这种情况:

    使用select编写服务器

    这是因为,虽然server的应用程序终止了,但tcp协议层的连接没有完全断开,因此不能再次监听同样的server端口。

    client终止时自动关闭socket描述符,server的TCP连接收到client发的FIN段后处于TIME_WAIT状态。TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,因为我们先Ctrl-C终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口。MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Linux上一般经过半分钟后 就可以再次启动server了。

  • 相关阅读:
    JsCV Core v0.2发布 & Javascript图像处理系列目录
    Javascript图像处理
    SOE开发之IMapServerSourceDescription
    SOE之JSONObject
    SOE开发之adddynamiclayertomapserver
    JavaScript 的 async/await
    ArcGIS Engine开发系列:将地图导出为图片的两种方法(ZZ)
    原型链
    更优美的javaScript(2)
    CSS选择器
  • 原文地址:https://www.cnblogs.com/MessiXiaoMo3334/p/10054617.html
Copyright © 2011-2022 走看看