最近在学习网络编程,觉得select这块的知识点确实比较难以理解,在学习socket网络通信机制时,只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序,(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞方式工作的程序,所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。下面详细介绍一下!
select在socket编程总自己认为还是很重要的。这种I/O复用技术,可以大大的提高效率。
I/O多路复用技术适用的场合:
(1)当客户处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用技术。
(2)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,要用到I/O复用。
(3)如果一个服务器既要处理TCP,又要处理UDP,要使用I/O复用。
(4)如果一个服务器要处理多个服务或多个协议,要使用I/O复用。
但是以上的几种要求也可以用多进程多线程来完成,那么这里用I/O复用技术的优点是,系统开销小,系统不必创建多线程多进程,也不必维护多进程和多线程,而大大减小了系统的开销。
select函数理解:
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
在网络程序中,一个进程同时处理多个文件描述符是很常见的情况
select()系统调用可以使进程检测同时等待的多个I/O设备,当没有设备准备好时,select()阻塞,其中任一设备准备好时,select()就返回
select的返回值有如下情况:1. 正常情况下返回就绪的文件描述符个数;
2. 经过了timeout时长后仍无设备准备好,返回值为0;
3. 如果select被某个信号中断,它将返回-1并设置errno为EINTR;
4. 如果出错,返回-1并设置相应的errno。
select中间的3个参数readfds, writefds, errorfds指定我们要让内核测试读,写,异常条件的描述符,如果对某一条件不感兴趣,可以把他设为空指针。
参数readfds指定了被读监控的文件描述符集;
参数writefds指定了被写监控的文件描述符集;
参数exceptfds指定了被例外条件监控的文件描述符集;
fd_set可以理解为一个集合。用来标识对应的描述符的状态。初始化是将文件描述符集合全设为0,如果哪个客户端准备好了要连接,则将客户端描述符对应的在描述符集合中的位置置为1.系统提供了4个宏对描述符集进行操作:
void FD_SET(int fd, fd_set *fdset); //设置文件描述符集fdset中对应于文件描述符fd的位(设置为1) void FD_CLR(int fd, fd_set *fdset); //清除文件描述符集fdset中对应于文件描述符fd的位(设置为 0 void FD_ISSET(int fd, fd_set *fdset); //判断文件描述符集fdset中有没有描述符fd void FD_ZERO(fd_set *fdset); //清除文件描述符集fdset中的所有位(既把所有位都设置为0)