[db:标题]
摘要:多路IO- poll 3.1简介 poll的机制与select类似,他们都是让内核在以线性的方法对文件描述符集合进行检测,根据描述符的状态进行具体的操作。并且poll和select在检测描述符集合时,会在检测的过程中频繁的进行用户区和内
多路IO- poll
3.1简介
poll的机制与select类似,他们都是让内核在以线性的方法对文件描述符集合进行检测,根据描述符的状态进行具体的操作。并且poll和select在检测描述符集合时,会在检测的过程中频繁的进行用户区和内核区的拷贝,随着文件描述符集合中的数量增大,开销也随之增大,效率也会变低。
select检测的文件描述符数量最大为1024个,而poll则没有数量限制。并且select可以跨平台,而poll只能在Linux系统中使用。
3.2 poll函数
头文件:#include <poll.h>
函数原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
函数参数:
fds:是一个struct pollfd类型的结构体数组,里面存储了要检测的文件描述符的信息,稍后详述。
nfds:数组实际有效内容的个数。
timeout:
-1 一直阻塞,直到检测的集合中有就绪的文件描述符(发送事件的),然后解除阻塞。
0 不阻塞,不管检测集合中有没有已经就绪的文件描述符,函数会马上返回。
大于0 阻塞指定的毫秒数之后,然后解除阻塞。
函数返回值:
大于0的整数:表示检测的集合中已就绪的文件描述符总个数。
-1:表示调用失败。
结构体struct pollfd的成员(三个):
int fd:委托内核检测的文件描述符。
short events:委托内核要检测文件描述符的事件。
short revents:文件描述符实际发送的事件,这是一个传出参数。
结构体struct pollfd事件表:
事件
常值
作为events的值
作为revents的值
说明
读事件
POLLIN
是
是
普通或优先带数据可读
POLLRDNORM
是
是
普通数据可读
POLLRDBAND
是
是
优先级带数据可读
POLLPRI
是
是
高优先级带数据可读
写事件
POLLOUT
是
是
普通或优先带数据可写
POLLWRNORM
是
是
普通数据可写
POLLWRBAND
是
是
优先级带数据可写
错误事件
POLLERR
是
发生错误
POLLHUP
是
发送挂起
POLLNVAL
是
描述不是打开的文件
3.3 使用poll实现高并发的步骤:
第一步:通过socket函数创建一个监听描述符。
第二步:通过bind函数将监听描述符和服务端本地地址进行绑定。
第三步:通过listen函数将监听文件描述符切换至监听状态。
第四步:自定义一个文件描述符集和结构体,然后对其初始化,然后准备一个变量用于记录最大描述符的值。
第五步:将监听文件描述符放入自定义文件描述集合下标为0的地方(不这样做的话集合为空,poll的第三参数是-1则会一直阻塞,如果是其他数则还是不行),然后进入无限循环
使用poll函数检测刚才自定义的文件描述符集合,如果集合中的某个描述符有信号了(读,写,错误等),那么则根据poll的第三参数来判断是否阻塞。(因为集合第0个位置是监听符,所以如果监听符有动静代表有客户端连接服务端了)
然后通过对监听描述符的读缓冲区进行判断,因为如果有客户端连接服务端,那么监听描述符的读缓存区就是这个客户端的信息,然后通过accept和监听文件描述符与刚才的客户端产生连接,返回一个与客户端产生连接的描述符,然后再拿这个与客户端建立连接的文件描述符存入自定义文件描述符集合供poll进行检测,加入之后记得跳出循环。
之后我们判断现在已建立链接的文件描述符是否是最大的,如果是则记录一下。
然后我们可以使用循环遍历的方法来遍历整个自定义文件描述符集合,来看看那个文件描述符是已建立链接的状态,然后通过使用这个文件描述符与对应的客户端进行数据传输,回应和处理客户端的各种请求等等。当回应完毕,处理完毕之后又或者客户端没有请求了,那么记得关闭这个与客户端建立连接的文件描述符,然后将这个文件描述符所在的自定义文件描述符集合中的位置置空,留给其他人使用。
第六步:可以不断重复第五步,如果所有的事情都做完了,那么可以关闭监听文件描述符。
