Linux poll()解析以及与select()对比
来源:互联网 发布:韩国漫画下载软件 编辑:程序博客网 时间:2024/06/05 04:52
Linux poll()解析
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于 socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select() 函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因 此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
返回值:
>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的 socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么 poll() 函数立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发 生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
-1: poll函数调用失败,同时会自动设置全局变量errno;
如果待检测的socket描述符为负值,则对这个描述符的检测就会被忽略,也就是不会对成员变量events进行检测,在events上注册的事件也会被忽略,poll()函数返回的时候,会把成员变量revents设置为0,表示没有事件发生;
另外,poll() 函数不会受到socket描述符上的O_NDELAY标记和O_NONBLOCK标记的影响和制约,也就是说,不管socket是阻塞的还是非阻塞 的,poll()函数都不会受到影响;而select()函数则不同,select()函数会受到O_NDELAY标记和O_NONBLOCK标记的影 响,如果socket是阻塞的socket,则调用select()跟不调用select()时的效果是一样的,socket仍然是阻塞式TCP通讯,相 反,如果socket是非阻塞的socket,那么调用select()时就可以实现非阻塞式TCP通讯;
strust pollfd结构说明:
typedef struct pollfd {
int fd; /* 需要被检测或选择的文件描述符*/
short events; /* 对文件描述符fd上感兴趣的事件 */
short revents; /* 文件描述符fd上当前实际发生的事件*/
} pollfd_t;
typedef unsigned long nfds_t;
如果是对一个描述符上的多个事件感兴趣的话,可以把这些常量标记之间进行按位或运算就可以了;
比如:对socket描述符fd上的读、写、异常事件感兴趣,就可以这样做:struct pollfd fds;
fds[nIndex].events=POLLIN | POLLOUT | POLLERR;
当 poll()函数返回时,要判断所检测的socket描述符上发生的事件,可以这样做: struct pollfd fds;
检测可读TCP连接请求:
if((fds[nIndex].revents & POLLIN) == POLLIN){ //接收数据/调用accept()接收连接请求 }
检测可写:
if((fds[nIndex].revents & POLLOUT) == POLLOUT){ //发送数据 }
检测异常:
if((fds[nIndex].revents & POLLERR) == POLLERR){ //异常处理 }
每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。revents域是文件描述符的操作结果事件掩码。内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回。合法的事件如下:
POLLIN 有数据可读。
POLLRDNORM 有普通数据可读。
POLLRDBAND 有优先数据可读。
POLLPRI 有紧迫数据可读。
POLLOUT 写数据不会导致阻塞。
POLLWRNORM 写普通数据不会导致阻塞。
POLLWRBAND 写优先数据不会导致阻塞。
POLLMSG SIGPOLL 消息可用。
POLLER 指定的文件描述符发生错误。
POLLHUP 指定的文件描述符挂起事件。
POLLNVAL 指定的文件描述符非法。
这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。使用poll()和select()不一样,你不需要显式地请求异常情况报告。
POLLIN | POLLPRI等价于select()的读事件,POLLOUT |POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM |POLLRDBAND,而POLLOUT则等价于POLLWRNORM。
timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数值表示无限超时;timeout为0指示poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。
返回值和错误代码
成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,poll()返回0;失败时,poll()返回-1,并设置errno为下列值之一:
EBADF 一个或多个结构体中指定的文件描述符无效。
EFAULT fds指针指向的地址超出进程的地址空间。
EINTR 请求的事件之前产生一个信号,调用可以重新发起。
EINVAL nfds参数超出PLIMIT_NOFILE值。
ENOMEM 可用内存不足,无法完成请求。
10、Multiplexed I/O
Linux提供了三个multiplexed I/O:select, poll, 和 epoll
select提供了同步multiplexing I/O:
Cpp代码
1. #include <sys/time.h>
2. #include <sys/types.h>
3. #include <unistd.h>
4.
5. int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
6. FD_CLR(int fd, fd_set *set);//从set中清除fd
7. FD_ISSET(int fd, fd_set *set);//判断fd是否在set中
8. FD_SET(int fd, fd_set *set);//将fd添加到set中
9. FD_ZERO(fd_set *set);//fd_set很多系统实现为bit arrays,将所有的文件描述符从fd_set中清空
调用select将会被阻塞直到所给的文件描述准备好I/O操作或则给定的timeout超时。
n 为 文件描述符集合中的最大值+1 调用者需要自行计算
readfds 被监控是否可以读
writefds 被监控是否可以写
exceptfds 被监控是否发生异常
timeout 超时时间,Linux返回时会被修改成剩余的时间。
timeval的定义:
Cpp代码
1. #include <sys/time.h>
2.
3. struct timeval {
4. long tv_sec; /*second */
5. long tv_usec; /* microsecods */
6. };
成功返回准备好I/O操作的文件描述符数,指定了timeout,则可能返回0,error返回-1
例子:
Cpp代码
1. #include <stdio.h>
2. #include <sys/time.h>
3. #include <sys/types.h>
4. #inlcude <unistd.h>
5.
6. #define TIMEOUT 5
7. #define BUF_LEN 1024
8.
9. int main(void){
10. struct timeval tv;
11. fd_set readfds;
12. int ret;
13.
14. FD_ZERO(&readfds);
15. FD_SET(STDIN_FILENO,&readfds);
16.
17. tv_tv_sec = TIMEOUT;
18. tv.tv_usec = 0;
19.
20. ret = select(STDIN_FILENO + 1,
21. &readfds,
22. NULL,
23. NULL,
24. &tv);
25. if(ret == -1){
26. perror("select");
27. return 1;
28. }else if(!ret){
29. printf("%d seconds elapse.\n", TIMEOUT);
30. return 0;
31. }
32.
33. if(FD_ISSET(STDIN_FILENO, &readfds)){
34. char buf[BUF_LEN + 1];
35. int len;
36.
37. len = read(STDIN_FILENO,buf,BUF_LEN);
38. if(len == -1){
39. perror("read");
40. return 1;
41. }
42. if(len){
43. buf[len] = '\0';
44. printf("read: %s\n", buf);
45. return 0;
46. }
47. }
48. fprintf(stderr,"This should not happen!\n");
49. return 1;
50. }
可以将select做为a portable way to sleep使用
Cpp代码
1. struct timeval tv;
2.
3. tv.tv_sec = 0;
4. tv.tv_usec = 500;
5.
6. select(0, NULL, NULL, NULL, &tv);
pselect:
Cpp代码
1. #include<sys/select.h>
2.
3. int pselect(int n, fd_set *readfds, fd_set *writefds,fd_set *exceptfds,
4. const struct timespec *timeout, const sigset_t *sigmask);
pselect和select的不同点:
1、使用timespec而不是timeval结构作为timeout参数,timespec使用秒和纳秒,理论上更高级,但是实际上
即使是微妙也不是可靠地。
2、pselect不会修改timeout参数,所以timeout不需要重新初始化。
3、select没有sigmask参数。
pselect解决一下竞争问题:
signal可能会设置一些全局的flag,调用select之前要检查flag.这样,如果信号在检查flag和调用select之间到来,
修改了flag,那么程序将会永远的阻塞。pselect解决了这个问题。
poll:
Cpp代码
1. #include<sys/poll.h>
2.
3. int poll(struct pollfd *fds, unsigned int nfds, int timeout);
fds pollfd的数组,用来监控是否可以读写,nfds数组的大小
timeout 超时时间。
pollfd:
Cpp代码
1. #include <sys/poll.h>
2.
3. struct pollfd{
4. int fd;/* file descriptor */
5. short events; /* requested event to watch,is a bitmask */
6. short revents; /* returned events witnessed,is a bitmask */
7. };
合法的events:
POLLIN: 有数据可读
POLLRDNORM: 有normal data可以读
POLLRDBAND: 有priority data可读
POLLPRI: 有urgent data可读
POLLOUT: 可以无阻塞的写
POLLWRNORM: 可以无阻塞的写normal data
POLLWRBAND: 可以无阻塞的写priority data
POLLMSG: 一个SIGPOLL message存在
除了以上revents:
POLLER: 文件描述符错误
POLLHUP: 文件描述符发生hung up 事件
POLLINVAL: 文件描述符不合法
和select相比,不需要显示指定exception fds
POLLIN|POLLPRI == select read event
POLLOUT|POLLWRBAND == select write event
POLLIN == POLLRDNORM | POLLRDBAND
POLLOUT == POLLWRNORM
timeout超时时间millisecond
例子:
Cpp代码
1. #include <stdio.h>
2. #include <unistd.h>
3. #include <sys/poll.h>
4.
5. #define TIMEOUT 5
6.
7. int main(void){
8. struct pollfd fds[2];
9. int ret;
10.
11. fds[0].fd = STDIN_FILENO;
12. fds[0].events = POLLIN;
13.
14. fds[1].fd = STDOUT_FILENO;
15. fds[1].events = POLLOUT;
16.
17. ret = poll(fds,2,TIMEOUT * 1000);
18.
19. if(ret == -1){
20. perror("poll");
21. return 1;
22. }
23.
24. if( ! ret ){
25. printf("%s second elapsed.\n",TIMEOUT);
26. return 0;
27. }
28.
29. if(fds[0].revents & POLLIN)
30. printf("stdin is readable\n");
31. if(fds[1].revents & POLLOUT)
32. printf("stdout is writable\n");
33. return 0;
34. }
不需要每次重新设置pollfd结构,revents每次会被内核先清空。
ppoll:
ppoll之poll和pselect之select一样,但是ppoll是linux特有的接口。
Cpp代码
1. #include <sys/poll.h>
2.
3. int ppoll(struct pollfd *fds,nfds_t nfds,const struct timespec *timeout,
4. const sigset_t *sigmask);
poll VS select:
poll有点:
1、poll不需要用户计算最大文件描述符+1作为第一个参数
2、poll对于文件描述符比较大的,更高效,select使用bit map,需要比较每一个bit
3、poll文件描述符集合大小是静态的,一个固定大小的pollfd数组。
4、select文件描述符结合参数作为返回值被重新构造,所以每次需要重新初始化,poll使用了
分开的input(events filed)和out(revents fields),使得pollfd数组可以被重用。
5、select中的timeout在返回的时候没有被定义,所以可移植的代码需要重新初始化,pselect没有这个问题。
select优点:
1、select更具有可移植性,有些UNIX不支持poll
2、select提供了更好的timeout机制:精确到微秒。
epoll比poll和select更高级,是Linux专有的接口。
0 0
- Linux poll()解析以及与select()对比
- Linux select、poll、epoll解析
- linux 下 select ,poll ,epoll 对比
- Linux/Unix select函数 及select/poll与epoll的对比
- Linux/Unix select函数 及select/poll与epoll的对比
- select poll epoll 对比
- select/poll/epoll对比
- Linux/Unix网络编程 epoll和select/poll的对比
- Linux select/poll和epoll实现机制对比
- linux 驱动学习之poll与select
- linux select与poll的区别
- linux select与poll的区别
- select、poll、epoll区别对比
- select、poll、epoll区别对比
- select/poll/epoll对比分析
- EPOLL&POLL*SELECT对比区别
- linux select poll
- linux select&poll
- 堆和栈的区别(转过无数次的文章)
- IP分片详解
- 第十四周项目1(4)——验证平衡二叉树相关算法
- 第十五周项目2用哈希法组织关键字
- 第十四周项目1-(3)-验证二叉排序树相关算法
- Linux poll()解析以及与select()对比
- LocalStorage
- 使用SSM框架搭建Web服务器实现登录功能(Spring+SpringMVC+Mybatis)
- iBaits中SqlMapClientTemplate及SqlMapClientTemplate的使用
- 第十三周 项目2:Kruskal算法的验证
- mysql root用户关闭写权限后无法修改回来
- [绍棠] 进入某一界面强制横屏
- openCV for python 学习(一):环境搭建与图片显示
- 第十四周 项目2 二叉排序树中查找路径