Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
多路复用
学习方法!!!!!!
(1)原理:多路复用就像一个电子警察,监测IO口的数据收发的
疑问:IO如何表示 --》文件描述符表示
linux应该有定义变量专门存放所有我需要监测的文件描述符(IO口)
linux中定义fd_set类型专门存放你想要监测的文件描述符
如何实现监测接收和监测发送的
使用多路复用的基本思路:
第一步:想清楚你的代码究竟要监测哪些文件描述符(IO口)
第二步:定义fd_set类型变量存放你想要监测的文件描述符
第三步:调用select监测
第四步:判断是否真的发生了你想要监测的状态改变(读,写,异常就绪)
专业术语:
fd_set类型 --》称作文件描述符集合
(2)相关接口函数
第一个函数
#include <sys/select.h>
int select(int nfds, fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); //多路复用的函数
返回值:(重点) 成功 >0
失败 -1
超时 0
参数:nfds(重点) --》你想要监测的所有文件描述符中最大的那个+1
readfds --》你想监测文件描述符的读就绪(是否有数据可读)
writefds --》你想监测文件描述符的写就绪(是否有数据可写)
errorfds --》你想监测文件描述符的异常就绪(是否发生错误异常)
struct timeval --》存放超时时间的,如果不设置超时,写成NULL(永久监测)
{
tv_sec; //秒
tv_usec; //微秒
}
重点重点重点:select如果监测多个文件描述符的状态改变,如果某个文件描述符发生了状态改变,那么其他没有发生状态改变的文件描述符会被自动从集合中剔除
select如果没有检测到想要的状态改变,会阻塞(如果没有设置超时,会一直阻塞,如果设置了超时,时间一到就立马解除阻塞)
如果是循环调用select,那么文件描述符需要在循环里面重新添加
扩展:select也可以用于监测硬件设备的文件描述符(比如:监测串口)
第二组函数(操作fd_set)
void FD_CLR(int fd, fd_set *fdset);//将文件描述符fd从集合中删除
int FD_ISSET(int fd, fd_set *fdset);//判断fd在不在集合中
返回值非零说明是成员
返回值0说明不是成员
void FD_SET(int fd, fd_set *fdset);//将fd添加到集合中
void FD_ZERO(fd_set *fdset);//清空文件描述符集合