zoukankan      html  css  js  c++  java
  • IO复用_select函数

    select函数:

    #include <sys/select.h>
    #include <time.h>
    #include <sys/types.h>
    #include <unistd.h>
    int select(int nfds,
                   fd_set*readfds,
                   fd_set*writefds,
                   fd_set*exceptfds,
                   struct timeval*timeout);

    参数含义:

    • nfds:一个整型变量,它比所有文件描述符集合中的文件描述符的最大值大1。使用select的时候,必须计算最大值的文件描述符的值,将值通过nfds传入。
    • readfds:这个文件描述符集合监视文件集中的任何文件是否有数据可读,当select()返回的时候,readfds将清除其中不可读的文件描述符,只留下可读的文件描述符,即可以被recv()、read()等进行读操作。
    • writefds:这个文件描述符集合监视文件集中的任何文件是否有数据可写,当select()返回的时候,readfds将清除其中不可写的文件描述符,只留下可写的文件描述符,即可以被send()、write()等进行读操作。
    • exceptfds:这个文件集合将监视文件中的任何文件是否发生错误,其实,它还能用于监视带外数据OOB,带外数据使用MSG_OOB标志发送到套接字上。当select()返回时,readfds将清除其中的其他文件描述符,只留下可读的OOB数据。
    • timeout:设置在select()所监视的文件集合中的事件没有发生时,最长的等待时间,当超过这个时间时,函数返回。当超时返回为NULL时,表示阻塞操作,会一直等待,直到某个监视的文件集中的某个文件描述符符合返回条件。当timeout的值为0时,select()会立即返回。
    • sigmask:信号

    返回值:

    当返回大于0的正值:监视的文件集合中的文件描述符符合上述要求。

    当等于0时:超时。

    当为-1时:发生错误

    struct timeval结构:

    struct timeval
    {
           time_t tv_sec;                //
           long tv_usec;                 // 微秒,即1/1000000s
    }

    另外,还有4个宏操作文件描述符的集合:

    FD_ZERO():清理文件描述符集合;

    FD_SET():向某个文件描述符集合中加入文件描述符;

    FD_CLR():从某个文件描述符集合中取某个文件描述符;

    FD_ISSET():测试某个文件描述符是否为某个集合中的一员。

    注:文件描述符的集合存在最大的限制,其最大值为FD_SETSIZE,当超出最大值时,发生不可预料的事。同时,可以修改这个值,但是监视集合的效率会降低,是因为select()轮询是线性的。在这里,有个更加牛B的的函数,请查看epoll:epoll没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于2048, 一般来说这个数目和系统内存关系很大。最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。在内存拷贝上,epoll在这点上使用了“共享内存”,这个内存拷贝也省略了。

    附加:使用select()写的IO复用循环服务器模型的例子

      1 #include <sys/types.h>
      2 #include <sys/socket.h>
      3 #include <netinet/in.h>
      4 #include <time.h>
      5 #include <string.h>
      6 #include <stdio.h>
      7 #include <pthread.h>
      8  #include <sys/select.h>
      9 #define BUFFLEN 1024
     10 #define SERVER_PORT 8888
     11 #define BACKLOG 5
     12 #define CLIENTNUM 1024/*最大支持客户端数量*/
     13 
     14 /*可连接客户端的文件描述符数组*/
     15 int connect_host[CLIENTNUM];
     16 int connect_number =  0;
     17 
     18 //处理客户端请求函数
     19 static void *handle_request(void *argv)
     20 {    
     21     time_t now;        /*时间*/
     22     char buff[BUFFLEN];/*收发数据缓冲区*/
     23     int n = 0;
     24     
     25     int maxfd = -1;/*最大侦听文件描述符*/
     26     fd_set scanfd;    /*侦听描述符集合*/
     27     struct   timeval   timeout;     /*超时*/
     28     timeout.tv_sec     =   1; /*   阻塞1秒后超时返回   */     
     29     timeout.tv_usec   =   0;     
     30     
     31     int i = 0;
     32     int err  = -1;
     33     for(;;)
     34     {   
     35         /*最大文件描述符值初始化为-1*/        
     36         maxfd = -1;
     37         FD_ZERO(&scanfd);/*清零文件描述符集合*/
     38         for(i=0;i<CLIENTNUM;i++)/*将文件描述符放入集合*/
     39         {
     40             if(connect_host[i] != -1)/*合法的文件描述符*/
     41             {
     42                 FD_SET(connect_host[i], &scanfd);/*放入集合*/
     43                 if(maxfd <     connect_host[i])/*更新最大文件描述符值*/
     44                 {
     45                     maxfd = connect_host[i];
     46                 }
     47             }
     48         }
     49         /*select等待*/
     50         err = select(maxfd + 1, &scanfd, NULL, NULL, &timeout) ;        
     51         switch(err)
     52         {
     53             case 0:/*超时*/
     54                 break;
     55             case -1:/*错误发生*/
     56                 break;
     57             default:/*有可读套接字文件描述符*/
     58                 if(connect_number<=0)
     59                     break;
     60                 for(i = 0;i<CLIENTNUM;i++)
     61                 {
     62                     /*查找激活的文件描述符*/
     63                     if(connect_host[i] != -1)
     64                     if(FD_ISSET(connect_host[i],&scanfd))   
     65                     {  
     66                         memset(buff, 0, BUFFLEN);/*清零*/
     67                         n = recv(connect_host[i], buff, BUFFLEN,0);/*接收发送方数据*/
     68                         if(n > 0 && !strncmp(buff, "TIME", 4))/*判断是否合法接收数据*/
     69                         {
     70                             memset(buff, 0, BUFFLEN);/*清零*/
     71                             now = time(NULL);/*当前时间*/
     72                             sprintf(buff, "%24s
    ",ctime(&now));/*将时间拷贝入缓冲区*/
     73                             send(connect_host[i], buff, strlen(buff),0);/*发送数据*/
     74                         }
     75                         /*更新文件描述符在数组中的值*/
     76                         connect_host[i] = -1;
     77                         connect_number --;    /*客户端计数器减1*/    
     78                         /*关闭客户端*/
     79                         close(connect_host[i]);                            
     80                     } 
     81                 }
     82                 break;     
     83         }          
     84     } 
     85     
     86     return NULL;
     87 }
     88 
     89 //处理客户端连接函数
     90 static void *handle_connect(void *argv)
     91 {    
     92     int s_s = *((int*)argv) ;/*获得服务器侦听套接字文件描述符*/
     93     int s_c = -1;/*连接客户端文件描述符*/
     94     struct sockaddr_in from;
     95     int len = sizeof(from);
     96     /*接收客户端连接*/
     97     for(;;)
     98     {
     99         int i = 0;
    100         int s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端的请求*/
    101         printf("a client connect, from:%s
    ",inet_ntoa(from.sin_addr));
    102         /*查找合适位置,将客户端的文件描述符放入*/                
    103         for(i=0;i<CLIENTNUM;i++)
    104         {
    105             if(connect_host[i] == -1)/*找到*/
    106             {
    107                 /*放入*/
    108                 connect_host[i]= s_c;
    109                 
    110                 /*客户端计数器加1*/
    111                 connect_number ++;
    112                 /*继续轮询等待客户端连接*/
    113                 break;                        
    114             }    
    115         }        
    116     }    
    117     return NULL;
    118 }
    119 
    120 int main(int argc, char *argv[])
    121 {
    122     int s_s;    /*服务器套接字文件描述符*/
    123     struct sockaddr_in local;    /*本地地址*/    
    124     int i = 0;
    125     memset(connect_host, -1, CLIENTNUM);
    126     
    127     /*建立TCP套接字*/
    128     s_s = socket(AF_INET, SOCK_STREAM, 0);
    129     
    130     /*初始化地址接哦股*/
    131     memset(&local, 0, sizeof(local));/*清零*/
    132     local.sin_family = AF_INET;/*AF_INET协议族*/
    133     local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
    134     local.sin_port = htons(SERVER_PORT);/*服务器端口*/
    135     
    136     /*将套接字文件描述符绑定到本地地址和端口*/
    137     int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
    138     err = listen(s_s, BACKLOG);/*侦听*/
    139     
    140     pthread_t  thread_do[2];/*线程ID*/
    141     /*创建线程处理客户端连接*/
    142     pthread_create(&thread_do[0],/*线程ID*/
    143                     NULL,/*属性*/
    144                     handle_connect,/*线程回调函数*/
    145                     (void*)&s_s);        /*线程参数*/
    146     /*创建线程处理客户端请求*/                    
    147     pthread_create(&thread_do[1],/*线程ID*/
    148                     NULL,/*属性*/
    149                     handle_request,/*线程回调函数*/
    150                     NULL);        /*线程参数*/
    151     /*等待线程结束*/
    152     for(i=0;i<2;i++)
    153         pthread_join(thread_do[i], NULL);
    154     
    155     close(s_s);
    156     
    157     return 0;        
    158 }
    作者:orange1438
    出处:http://www.cnblogs.com/orange1438/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    HttpWebRequest.GetRequestStream方法timeout的原因及解决办法
    C#随机函数random()典型用法集锦
    windows 2008 开启默认共享
    Window xp命令大全
    大并发处理解决方案
    库特Z配置
    SQL Server 返回了错误 21(设备未就绪。) 解决方法
    C# 执行bat批处理文件
    sql索引从入门到精通(十亿行数据测试报告)
    DataTable使用时的小问题
  • 原文地址:https://www.cnblogs.com/orange1438/p/4614249.html
Copyright © 2011-2022 走看看