Linux-C网络编程之select函数

开门见山,如果我们要对多个客户端连接的多个事件进行操作,首先会想到建立多个线程或进程让其去各自进行,这也是最简单的模式。
但对每一个线程或进程而言,无论连接是否有事件发生,都必须随时待命,也就是说, ** 每一个对象都必须有一个线程或进程与之一一对应,直到对象销毁 ** 。
可想而知,当连接量规模变大后,系统需要在很多个线程或进程之间进行切换,时间与空间上的开销巨大,也就是说,这种模式下,程序能承载对象的最大值是很小的(一般数百
个)。

那么,就要提到 ** _ select _ ** 函数了。man select得到函数参数及头文件如下

       #include <sys/select.h>
       #include <sys/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);

       void FD_CLR(int fd, fd_set *set);//删除fd
       int  FD_ISSET(int fd, fd_set *set);//检测fd是否存在于组
       void FD_SET(int fd, fd_set *set);//添加fd
       void FD_ZERO(fd_set *set);//对组进行清零

** nfds ** :整型变量,是指集合中所有文件描述符的范围,假如集合中最大文件描述符为 ** max ** ,那么 ** ndfs=max+1
** ,千万不要理解为文件描述符的总量。
** readfds ** :指针,指向一组等待可读性检查的套接字集合。
** writefds ** :指针,指向一组等待可写性检查的套接集合。
** exceptfds ** :指针,指向一组等待错误检查的套接集合。
** timeout ** : ** select() ** 最多等待时间,如果为 ** NULL ** ,则相当于阻塞(等待直到事件发生),若为 ** 0 ** 则为非阻塞(没有事件便立即返回),其他值代表若有事件或是超时则返回。

** 函数流程解释及样例 **

    int ret,i,fd[MAX],MAX;
    struct timeval timeout;
    fd_set readfds;
    while(1)
    {
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        FD_ZERO(&readfds);//组清零初始化
        for(i=0;i<MAX;i++)
        {
            FD_SET(fd[i], &readfds);
        }
        ret select(MAX,&readfds, NULL,NULL,&timeout);//仅演示读监听,其他同理
    }

_ 将select放在循环体内时,有两点是要特别注意的 _

<1>timeout的初始化,因为select在执行时,对timeout进行的实际是类似于i–的操作,所以循环体内每次都要重新初始化,否则timeout
的值将永久是0;
<2>文件描述符集合的初始化,因为集合的机理类似于二进制,FD_ZERO()后集合内全部归零(0000000),若FD_SET(5),则为(0100000)
,当selete在执行过程中,发现每个某个连接有事件产生时,便会将该套接字标志为1,没有事件的标志为0,执行完成后,若有事件产生,则可以FD_ISSET(f
d,&readfds)来判断fd是否有事件产生。
因此,每执行一次select函数,都要重新对集合进行初始化。

select()可以确定一个或多个套接口的状态,常用来实现单进程或单线程的多路复用。
也就是说,select可以在一个线程或进程内对多个连接的事件事件进行响应。

那么它是如何完成这个功能的呢,举个例子来说:
假如你在100家不同的店各订了一份外卖(不同的店收货点当然是不同的)。

  1. 如果用上述多进程或线程的模式来取外卖的话,你就要再找99个朋友帮你去各个收货点去等待。(多进程模式,哪来的手机!)
  1. 你有一盏名叫select的信号灯,你只需要守候在select前,每当一家或多家外卖要送到的时候,都会将信号灯点亮,那么问题来了,你只知道外卖送
    到了,但却并不知道到底是哪家,所以你需要亲自把100家外卖的送货点全部遍历一遍,取下已到的外卖,然后继续回到信号灯前等待。有什么优点呢,很显然,100个人才
    能完成的事你一个人就完成了,而且多个外卖可能会同时到,顺风路走了不少嘛。
    至于缺点嘛,当然是每次都要把100家收货点全部走一遍(减肥也没有这么拼的)
  1. 找 ** _ epoll _ **
    函数,它会给你一部手机,送货师傅外卖送到时可以给你打电话啦。有了手机,这一切该是多么完美,那么会是怎么个完美法呢,下章再谈吧。

ps:好困啊,年纪大了,熬不了夜了!