TCP/IP,Linux多路IO模型poll与代码示例
O、select本身使用上有些许不方便的地方,比如需要将所有描述符与select得到的fd_set遍历比较,比较麻烦,poll模型是select模型的升级版,使用起来更加方便一些。
一、poll函数以及参数
函数声明:
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
结构体声明:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
1、第一个参数类型为指针,标志符为复数fds,这说明传入的是一个结构体数组,而不是一个变量的地址,这个需要注意,如果不加s而是fd,则判断为变量地址。
2、第二个参数是结构体数组的最大文件描述符+1,这里和select传的数值没有区别。
3、第三个是超时时间,传入-1则阻塞等待,传入0则立即返回,传入>0则指定等待毫秒数,如果当前系统时间不够毫秒就会向上取值。
二、poll优于select的地方
1、文件描述符监控数量高于1024,select的监听上限为1024,想要突破需要重新编译内核。
2、poll中将用于监听的描述符和返回的描述符进行了分离,select中监听描述符算作返回值的一部分。
3、poll中将满足事件的描述组存放在数组中,缩小了搜索范围,不需要像select挨个遍历逐一判断。
三、poll数组的赋值:
struct pollfd fds[5000];
fds[0].fd = listenfd;
fds[0].events = POLLIN; //POLLIN/POLLOUT/POLLERR
fds[1].fd = fd1;
fds[1].events = POLLIN;
fds[2].fd = fd2;
fds[2].events = POLLIN;
poll(fds, 3, -1);
注意:
1、fds数组中的值在赋值的时候不需要给revents赋值,这个字段是POLL返回以后,满足事件的文件描述符的revents字段会由操作系统赋值,
2、这个字段的值与其监听的events对应,监听POLLIN则会赋值为POLLIN,用于判断并进行相应的操作。
3、如果对一个描述符要监听读和写,可以在poll数组中加一个同名描述符,改变监听事件,分别监听POLLIN和POLLOUT
4、事件的比较,使用if(revents & POLLIN),而不是使用==,
5、由于fds数组的大小是固定的,需要在定义时就确认,因此里面的描述符值需要初始化,一般可以将监听的描述符放在第一位,下标为0,后面的描述符全部初始化为-1,然后传入给poll
6、fds数组的长度是固定了的,因此需要使用一个int数据单独记录最大文件描述符的值,避免每次遍历整个数组造成资源浪费
四、poll返回后各个参数的利用
1、poll返回以后,其参数fds中会有某个或某些描述符的revents字段被操作系统赋了值,
2、依次遍历到最大文件描述符,检查每个描述符的状态,以及是否符合事件revents,出现了事件则执行指定函数,一般事件就是POLLIN,接受到了客户端的数据或者接受到了客户端的连接请求。</