select模型支持IO多路复用
,select函数如下
1 | int select ( |
逐个解释每个参数意义:
nfds:一个整型变量,表示比最大文件描述符+1
readfds: 这个集合监测读事件的描述符
,将要监听读事件的文件描述符放入readfds中,通过调用select,readfds中将没有就绪的读事件文件描述符清除,留下
就绪的读事件描述符,可以通过read或者recv来处理
writefds:这个集合监测写事件的描述符
,将要监听的写事件的文件描述符放入writefds中,通过调用select,writefds中没有就绪的写事件文件描述符被清除,留下
就绪的写事件描述符,可以通过write或者send来处理。
execptfds:这个集合在调用select后会存有错误的文件描述符
。根据Linux网络网络编程第二版中介绍,可以监视带外数据OOB,带外数据使用MSG_OOB标志发送
到套接字上,当select()函数返回的时候,readfds将清除其中的其他文件描述符,留下OOB数据
函数返回值:
当返回0时表示超时,-1表示有错误,大于0表示没有错误
。
当监视文件集中有文件描述符符合要求,即读文件描述符集合中有文件可读,写文件描述符集合中有文件可写,或者错误文件描述符集合中有错误的描述符,都会返回大于0的数
1 | timeval结构体解释 |
timeval指针为NULL,表示一直等待,直到有符合条件的描述符触发select返回
如果timeval中个参数均为0,表示立即返回
,否则在select没有符合条件的描述符,等待对应的时间和,然后返回
。另外需要了解一些select的操作宏函数
fd_set是一个SOCKET队列,以下宏可以对该队列进行操作:FD_CLR( s, fd_set *set) 从队列set删除句柄s;
FD_ISSET( s,fd_set *set) 检查句柄s是否存在与队列set中;
FD_SET( s, fd_set *set )把句柄s添加到队列set中;
FD_ZERO( fd_set *set ) 把set队列初始化成空队列.
看一个select的使用示例
1 | //前面是服务器socket的创建,绑定和监听 |
上面的例子结合了网上提供的一些demo,其实writeSet不一定要放入socket,当某个socket需要send内容时,再调用FD_SET(socket,&writeSet),写成功后再调用FD_CLR(socket,&writeSet);避免造成busyloop,
因为当缓冲区非空时,写事件是一直就绪的。