转载

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时:发生错误

IO复用_select函数

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:e poll没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于 2048, 一般来说这个数目和系统内存关系很大。 最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。在内存拷贝上,epoll在这点上使用了“共享内存”,这个内存拷贝也省略了----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/r/n",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/n",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/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
正文到此结束
Loading...