高性能编程之I/O复用之select简述

我是研究僧i 提交于 2019-12-03 01:44:52

很多场合都需要IO复用,比如:

1)客户端程序要同时处理多个socket.

2)客户端程序要同时处理用户输入和网络连接

3)TCP服务器要同时处理监听 socket和连接socket.

4)服务器要同时处理TCP请求和UDP请求。

5)服务器要同时监听多个端口,或者处理多种服务。

注意:IO复用本身是阻塞的。

LINUX下实现IO复用的系统调用有select,poll和epoll.本节就是来依次分析这三个系统调用。

 

关于select调用

select系统调用的用途是:

在一段时间内,监听用户感兴趣的文件描述符,对这些描述符的可读、可写和异常事件。

其实我感觉都是这样的,不然也不用叫IO复用了。

先看看原型吧,不然以后也记不住。

#include<sys/select.h>

int select ( int nfds, fd_set* readfds, fd_set* writefds, fd_set* excepfds, struct timeval* timeout);

先解释下各个参数的意思。

nfds: 最大的文件描述符加1,因为文件描述符是从0开始计数。

readfds,writefds,excepfds分别指向可读、可写和异常等事件对应的文件描述符集合。

当select返回时,内核将修改这几个集合来表示哪些文件描述符已经就绪。

注意:此时原先的三个参数集合已经被破坏了

fd_set结构体实际上是一个整型数组,数组的每个元素的每1位标记一个文件描述符。

注意:fd_set能容纳的文件描述符数量由FD_SETSIZE指定,所以有所限制。

平时编程时,可以用以下的几个宏来操作

#include<sys/select.h>

FD_ZERO---清除所有位

FD_SET-设置某个位

FD_CLR-清除某个位

FD_ISSET -测试某个位是否被设置

至于select API的timeout参数,则是用来设置select函数的超时时间,这个参数是个指针,

当select返回时,里面的值就是select等待了多久的时间。注意:select调用失败时,timeout值是不确定的。

timeout 0---select立即返回

timeout 非0---等待超时时间,然后返回。

timeout NULL--一直阻塞,直到某个文件描述符就绪。

select的返回值:所有可读,可写,异常文件描述符的总数。

失败时返回-1并且设置errno,这是一个进程级变量。

比如说,select是阻塞的,这个时候被信号中断,则select返回-1,并且errno为EINTR.表示被信号中断了。

~~~~~~~~~~~~以下是针对select调用来定义的

好的,这个时候,需要来确定下什么叫做socket可读。

1)socket内核接收缓冲区中的字节数>=其低水位SO_RCVLOWAT.

2) socket通信的对方关闭了连接,这个时候在缓冲区里有个文件结束符,此时读操作将返回0

3)监听socket上有连接请求,也就是连接队列里有可以accept的连接。

4)socket上有未处理的错误,此时我们可以用getsockopt来读取和清除该错误。

 

对于为什么有错误会设置为读条件满足,其实是因为你确实可以读,只不过读的话返回错误而已。

下列情况下可写

1)socket内核发送缓冲区里的可用字节数大于等于其低水位标记SO_SNDLOWAT.

也就是说有可用内核缓冲区供我们写一个socket.

2)socket的写操作被关闭,注意:此时可以写,但是写的结果是出发一个SIGPIPE信号。

3)socket使用非阻塞connect连接成功或者失败(超时)之后。

4)socket上有未处理的错误,此时我们可以用getsockopt来读取和清除该错误。

 

 

什么时候是一个socket的异常情况?

网络程序中,只有1种情况:socket上接收到带外数据。

其实就是这个意思:socket收到普通数据时select返回,然后这个 socket标记为可读。

如果收到带外数据,select 返回,然后这个socket标记为异常。

下一节,带外数据接收的时候需要指定MSG_OOB标识。

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!