一、poll()函数解析

不同与select使⽤用三个位图来表⽰示三个fdset的⽅方式,poll使⽤用⼀一个 pollfd的指针实现。pollfd结构包含了要监视的event和发⽣生的event,

不再使⽤用select“参数-值”传递的⽅方式。同时,pollfd并没有最⼤大数量限制(但是数量过⼤大后性能也是会下降)。 和select函数⼀一样,

poll返回后,需要轮询pollfd来获取就绪的描述符。

poll()函数:这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函数的声明:
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
参数说明:
struct pollfd:

  struct pollfd{

  int fd;              //文件描述符

  short events;    //等待的事件

  short revents;   //实际发生的的事件

  };

  

events和revents是通过对代表各种事件的标志进行逻辑或运算构建而成的。events包括要监视的事件,

poll用已经发生的事件填充revents。poll函数通过在revents中设置标志字符POLLHUP、POLLERR、POLLNVAL等来反映相关         条件的存在。

不需要在events中对于这些标志符相关的比特位进行设置。如果fd小于0, 则events字段被忽略,而revents被置为0.

标准中没有说明如何处理文件结束。文件结束可以通过revents的标识符POLLHUP或返回0字节的常规读操作来传达。

即使POLLIN或POLLRDNORM指出还有数据要读,POLLHUP也可能会被设置。因此,应该在错误检验之前处理正常的读操作

poll函数的事件标志符值:
常量 说明
POLLIN 普通或优先 带数据可读
POLLRDNORM                                      普通数据可读
POLLRDBAND 优先级带数据
      可读
POLLPRI 高优先级数据
      可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据
      可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一
个打开的文件
注:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。
      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;
二、poll应用实例
实例一:用poll监视输入输出
#include<stdio.h>
#include<poll.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char *argv[])
{struct pollfd _poll[1];_poll[0].fd=0;_poll[0].events=POLLIN;_poll[0].revents=0;int timeout=3000;int i=0;char buf[1024];
while(1)
{switch(poll(_poll,1,timeout)){case 0:printf("timeout");break;case -1:printf("poll");break;default:{for(i=0;i<2;i++){if((_poll[0].fd==0)&&(_poll[0].revents)&POLLIN){ssize_t s=read(0,buf,sizeof(buf)-1);if(s>0){buf[s]=0;if(strncmp(buf,"hello poll",10)==0){close(_poll[i].fd);return 1;}printf("this is test:poll:%s\n",buf);}}}}break;}
}
return 0;
}

事例二:poll实现服务器端:

#include<stdio.h>
#include<stdlib.h>
#include<poll.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
static void usage(char *proc)
{printf("usage:%s [local_ip] [local_port]\n",proc);
}
int startup(char* _ip,int _port)
{//create socketint sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 2;}//port multiplexingint flg=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flg,sizeof(flg));struct sockaddr_in local;local.sin_family=AF_INET;local.sin_addr.s_addr=inet_addr(_ip);local.sin_port=htons(_port);//bindif(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");return 3;}//listenif(listen(sock,10)<0){perror("listen");return 4;}return sock;
}
int main(int argc,char *argv[])
{if(argc!=3){usage(argv[0]);return 1;}int listen_sock=startup(argv[1],atoi(argv[2]));struct pollfd fd_set[2];fd_set[0].fd=listen_sock;fd_set[0].events=POLLIN;fd_set[0].revents=0;int timeout=2000;int n=sizeof(fd_set)/sizeof(fd_set[0]);struct sockaddr_in client;socklen_t len=sizeof(client);int i=1;for(;i<n;i++){fd_set[i].fd=-1;}int maxfd=0;while(1){switch(poll(fd_set,maxfd+1,timeout)){case 0:printf("timeout..\n");break;case -1:printf("poll");break;default:{for(i=0;i<n;i++){if((fd_set[i].fd==listen_sock)&& \(fd_set[i].revents)&POLLIN){int new_sock=accept(listen_sock,\(struct sockaddr*)&client,&len);if(new_sock<0){perror("accept");continue;}printf("get a new client:\n");int j=0;for(j=0;j<n;j++){if(fd_set[j].fd==-1){fd_set[j].fd=new_sock;fd_set[j].events=POLLIN;fd_set[j].revents=0;break;}}  if(j==n){close(new_sock);}if(j>maxfd){maxfd=j;}}else if((fd_set[i].fd>0)&& (fd_set[i].revents)&POLLIN){char buf[1024];ssize_t s=read(fd_set[i].fd,buf,sizeof(buf)-1);if(s>0){buf[s]='\0';printf("client:  %s\n",buf);write(fd_set[i].fd,buf,strlen(buf));}else if(s==0){close(fd_set[i].fd);int p=1;for(;p<n;i++){if((fd_set[p].fd!=-1)&&(p!=i)){int temp=fd_set[i].fd;fd_set[i].fd=fd_set[p].fd;fd_set[p].fd=temp;}}}}}}break;}}return 0;
}
三、总结
1、poll的优点
1)poll() 在应付大数目的文件描述符的时候相比于select速度更快,相对于select更加高效。
2)解决了select处理文件描述符有上限(默认1024)的限制。
2、poll缺点
1)、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。 
2)、与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符
 3)、事实上,同时连接的⼤大量客户端在⼀一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

Linux: I/O多路转接之poll(有图有代码有真相!!!)相关推荐

  1. Linux: shell 中命令代换 $() 和 ``(有图有代码有真相!!!)

    一.命令代换(命令替换) 由 ` ` 或  $() 括起来的也是一条命令,shell先执行该命令,再将结果立刻代换到当前命令行中. 简单例子: DATE=`date` echo $DATE DATE= ...

  2. IO多路转接之poll

    IO多路转接之poll 文章目录 IO多路转接之poll 一.Poll 一.Poll 1.函数原型: int poll(struct pollfd *fds, nfds_t nfds, int tim ...

  3. Linux: I/O多路转接之epoll(有图有代码有真相!!!)

    一.基本概念 epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下 ...

  4. I/O多路转接之poll——基于TCP协议

    1. 函数 a. 参数: (1)fds:是一个struct pollfd结构类型的指针,指向用于存放需要检测状态的Socket描述符: 每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便:特 ...

  5. I/O多路转接之poll 函数

    http://blog.csdn.net/li_ning_/article/details/52167224 poll 一.poll()函数: 这个函数是某些Unix系统提供的用于执行与select( ...

  6. I/O多路转接之poll,epoll

    1.poll 函数原型: #include <poll.h> int poll(struct pollfd fds[], nfds_t nfds, int timeout): 参数说明: ...

  7. Linux:I/O多路转接之select(有图有代码有真相!!!)

    一.select引入 一次 I/O 分为两个部分:1)等待数据就绪      2)进行数据转移 1.select 原理: select的原理就是减少等待数据就绪的比重,巧妙的利用等待队列机制让用户进程 ...

  8. Linux: 系统配置 crond 和 crontab(有图有代码有真相!!!)

    1.相关概述 linux下工作调度的种类有:at  ,  cron 一种是例行性的,就是每隔一定的周期来办某事. 一种是突发性的,就是做完这一次没有以后. crontab这个命令所设置的工作将会一直循 ...

  9. LInux:shell 彩色进度条实现(有图有代码有真相!!!)

    一.进度条原理(以前的博客详细讲述过):http://blog.csdn.net/sharp_up/article/details/55506555 二.颜色设置 // 字体颜范围(前景颜色):30~ ...

最新文章

  1. AD域管理系列(6)-- 常见处理
  2. ErWin简单使用说明
  3. Oracle查询慢的原因总结
  4. 伺服扭矩模式怎么控制_气液增压缸是怎么增压的?气液增压缸好用吗?气液增压缸的原理及其伺服控制...
  5. oracle ogg下载安装,牛刀小试Oracle GoldenGate--OGG安装(一)
  6. Java基础50道经典练习题(22年新版)
  7. 型机器人同人本子_唯美的人×机器人漫画《純情愛玩生化女友》
  8. 台式计算机拆卸步骤,拆装台式电脑主机的方法图解步骤
  9. 免费动态域名解析软件nat123技术性原理分析及使用方法说明
  10. 使用Postman获取北京时间校准接口API(Json格式)
  11. windows PE文件结构及其加载机制
  12. 区块链重要基础知识2——哈希函数的原理以及应用于区块头部
  13. 单机翻译软件android,计算机辅助翻译软件(Transmate)V7.3.0.1218 单机版
  14. 宋江是怎么当上老大的
  15. win10 mac的clover双系统后 win10时间不同步问题
  16. 浅谈快速开发平台:突破系统开发边界,赋能企业数字化!
  17. 快速识别区块链中的骗局
  18. 随机森林python
  19. MySql 如何将一维表变成二维表
  20. 内存和FLASH的区别

热门文章

  1. 解决 No projects are available for deployment to this server!
  2. 基于Sql Server 2008的分布式数据库的实践
  3. mybatis $和#源代码分析
  4. javascript 反斜杠\
  5. [原]详解如何将cocos2dx项目编译到Android平台上的(方式一:Cywin+NDK)
  6. image to pdf
  7. SEO技巧:好的域名是网站成功的开始
  8. Memcached常用操作
  9. 关于四种语言中substring()方法参数值的解析
  10. PHP_Smarty