I/O多路转接之poll 函数

http://blog.csdn.net/li_ning_/article/details/52167224

poll

一、poll()函数:

这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,自认为poll和select大同小异,下面是这个函数的声明:

[cpp] view plain copy
  1. #include <poll.h>  
  2.   
  3. int poll(struct pollfd *fds, nfds_t nfds, int timeout);  

参数:

1.第一个参数:一个结构数组,struct pollfd:

        fds:是一个struct pollfd结构类型的数组,每个数组元素都是一个pollfd结构,用于指定测试某个给定描述字fd的条件。存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况

结构如下:

[cpp] view plain copy
  1. struct pollfd{  
  2.  int fd;          //文件描述符  
  3.  short events;    //请求的事件  
  4.  short revents;   //返回的事件  
  5.  };  

  events和revents是通过对代表各种事件的标志进行逻辑或运算构建而成的。events包括要监视的事件(就是我需要关注的时间,是读?是写?还是出错?)poll用已经发生的事件填充revents。poll函数通过在revents中设置标志肌肤POLLHUP、POLLERR和POLLNVAL来反映相关条件的存在。不需要在events中对于这些标志符相关的比特位进行设置。如果fd小于0, 则events字段被忽略,而revents被置为0.标准中没有说明如何处理文件结束。文件结束可以通过revents的标识符POLLHUN或返回0字节的常规读操作来传达。即使POLLIN或POLLRDNORM指出还有数据要读,POLLHUP也可能会被设置。因此,应该在错误检验之前处理正常的读操作。

poll函数的事件标志符值:

常量说明
POLLIN普通或优先级带数据可读
POLLRDNORM普通数据可读
POLLRDBAND优先级带数据可读
POLLPRI高优先级数据可读
POLLOUT普通数据可写
POLLWRNORM普通数据可写
POLLWRBAND优先级带数据可写
POLLERR发生错误
POLLHUP发生挂起
POLLNVAL描述字不是一个打开的文件

  注意:

        1)后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。

  2)第二个参数nfds:要监视的描述符的数目。

  3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果  它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。 

timeout值说明
INFTIM永远等待
0立即返回,不阻塞进程
>0
等待指定数目的毫秒数


如果是对一个描述符上的多个事件感兴趣的话,可以把这些常量标记之间进行按位或运算就可以了;

比如:

对socket描述符fd上的读、写、异常事件感兴趣,就可以这样做:

[cpp] view plain copy
  1. struct pollfd  fds;  
  2.   
  3. fds[index].events=POLLIN | POLLOUT | POLLERR;  

当 poll()函数返回时,要判断所检测的socket描述符上发生的事件,可以这样做:

[cpp] view plain copy
  1. struct pollfd  fds;  
  2.   
  3. //检测可读TCP连接请求:  
  4. if((fds[nIndex].revents & POLLIN) == POLLIN)  
  5. {  
  6. <span style="white-space:pre">    </span>//接收数据,调用accept()接收连接请求  
  7. }  
  8.   
  9. //检测可写:  
  10. if((fds[nIndex].revents & POLLOUT) == POLLOUT)  
  11. {  
  12. <span style="white-space:pre">    </span>//发送数据  
  13. }  
  14.   
  15. //检测异常:  
  16. if((fds[nIndex].revents & POLLERR) == POLLERR)  
  17. {  
  18. <span style="white-space:pre">    </span>//异常处理  
  19. }  
二、实例TCP服务器的服务器程序

[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/socket.h>  
  5. #include <sys/types.h>  
  6. #include <netinet/in.h>  
  7. #include <netdb.h>   
  8. #include <string.h>  
  9. #include <errno.h>  
  10. #include <poll.h>   //for poll  
  11.   
  12. #define LISTENQ 1024  
  13. #define MAXLINE 1024  
  14. #define OPEN_MAX 50000  
  15.   
  16. #ifndef INFTIM   
  17. #define INFTIM -1   
  18. #endif               
  19.   
  20. int start_up(char* ip,int port)  //创建一个套接字,绑定,检测服务器  
  21. {  
  22.   //sock  
  23.   //1.创建套接字  
  24.   int sock=socket(AF_INET,SOCK_STREAM,0);     
  25.   if(sock<0)  
  26.   {  
  27.       perror("sock");  
  28.       exit(0);  
  29.   }  
  30.     
  31.   //2.填充本地 sockaddr_in 结构体(设置本地的IP地址和端口)  
  32.   struct sockaddr_in local;         
  33.   local.sin_port=htons(port);  
  34.   local.sin_family=AF_INET;  
  35.   local.sin_addr.s_addr=inet_addr(ip);  
  36.   
  37.   //3.bind()绑定  
  38.   if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)   
  39.   {  
  40.       perror("bind");  
  41.       exit(1);  
  42.   }  
  43.   //4.listen()监听 检测服务器  
  44.   if(listen(sock,back_log)<0)  
  45.   {  
  46.       perror("sock");  
  47.       exit(1);  
  48.   }  
  49.   return sock;    //这样的套接字返回  
  50. }  
  51.       
  52. int main(int argc, char *argv[])  
  53. {  
  54.   int i, maxi, connfd, sockfd;  
  55.   int nready;  
  56.   ssize_t n;  
  57.   socklen_t clilen;  
  58.   
  59.   struct sockaddr_in servaddr;  
  60.     socklen_t len=sizeof(servaddr);   
  61.   
  62.    char buf[BUFSIZ];  
  63.     struct pollfd client[OPEN_MAX]; // 用于poll函数第一个参数的数组,存放每次的文件描述符个数  
  64.   if( argc != 3 )  
  65.     {  
  66.        printf("Please input %s <hostname>\n", argv[0]);  
  67.      exit(2);  
  68.     }  
  69.   
  70.         int listenfd=start_up(argv[1],argv[2]);      //创建一个绑定了本地 ip 和端口号的套接字描述符  
  71.           
  72.       client[0].fd = listenfd;         //将数组中的第一个元素设置成监听描述字  
  73.       client[0].events = POLLIN;       //将测试条件设置成普通或优先级带数据可读(感兴趣的事件读、写、出错),此处书中为POLLRDNORM,*/  
  74.         client[0].revents = 0;           //真正发生的事件  
  75.   
  76.       for(i = 1;i < OPEN_MAX; ++i)     //数组中的其它元素将暂时设置成不可用  
  77.         {  
  78.             client[i].fd = -1;  
  79.         }  
  80.           
  81.       maxi = 0;  
  82.        while(1)  
  83.       {  
  84.          nready = poll(client, maxi+1,INFTIM);          //将进程阻塞在poll上  
  85.          if( client[0].revents & POLLIN)                //先测试监听描述字  
  86.          {  
  87.                 connfd = accept(listenfd,(struct sockaddr*)&servaddr, &clilen);  
  88.   
  89.               for(i = 1; i < OPEN_MAX; ++i)  
  90.                 {  
  91.                     if( client[i].fd < 0 )  
  92.                   {  
  93.                       client[i].fd = connfd;      //将新连接加入到测试数组中  
  94.                      client[i].events = POLLIN;  //POLLRDNORM; 测试条件普通数据可读  
  95.                       break;  
  96.                   }  
  97.                 if( i == OPEN_MAX )  
  98.                 {  
  99.                         printf("too many clients"); //连接的客户端太多了,都达到最大值了  
  100.                     exit(1);  
  101.                 }  
  102.   
  103.                 if( i > maxi )  
  104.                     maxi = i;        //maxi记录的是数组元素的个数  
  105.   
  106.                 if( --nready <= 0 )  
  107.                     continue;            //如果没有可读的描述符了,就重新监听连接  
  108.                 }  
  109.           }  
  110.   
  111.           for(i = 1; i <= maxi; i++)  //测试除监听描述字以后的其它连接描述字  
  112.           {  
  113.                 if( (sockfd = client[i].fd) < 0) //如果当前描述字不可用,就测试下一个  
  114.                   continue;  
  115.   
  116.               if(client[i].revents & (POLLIN | POLLERR))//如果当前描述字返回的是普通数据可读或出错条件  
  117.               {  
  118.                  if( (n = read(sockfd, buf, MAXLINE)) < 0) //从套接口中读数据  
  119.                  {  
  120.                       if( errno == ECONNRESET) //如果连接断开,就关闭连接,并设当前描述符不可用  
  121.                       {  
  122.                          close(sockfd);  
  123.                          client[i].fd = -1;  
  124.                       }  
  125.                       else  
  126.                           perror("read error");  
  127.                   }  
  128.                 else if(n == 0) //如果数据读取完毕,关闭连接,设置当前描述符不可用  
  129.                   {  
  130.                       close(sockfd);  
  131.                       client[i].fd = -1;  
  132.                   }  
  133.                   else  
  134.                       write(sockfd, buf, n); //打印数据  
  135.                if(--nready <= 0)  
  136.                    break;  
  137.               }  
  138.           }  
  139.      }  
  140.      exit(0);  
  141.  }  
赐教!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

链表相关笔试面试题

1.判断两个链表是否相交 两个链表是否相交可分为以下几种情况     &#xff08;1&#xff09;两个链表都不带环&#xff0c;此时两个链表所对应的最后一个节点是相等的     &#xff08;2&#xff09;两个链表一个带环&#xff0c;一个不带环&#xff0c;两个链表一定…

Linux经典问题—五哲学家就餐问题

http://m.blog.csdn.net/aspenstars/article/details/70149038 一、问题介绍 由Dijkstra提出并解决的哲学家进餐问题(The Dinning Philosophers Problem)是典型的同步问题。该问题是描述有五个哲学家共用一张圆桌&#xff0c;分别坐在周围的五张椅子上&#xff0c;在圆桌上有五…

修改之前的myshell使之支持输入输出重定向

1.open函数     这个函数是打开一个文件&#xff08;文件名叫pathname),以 flag 权限打开&#xff0c;flag 包括了以下几种 O_RDONLY&#xff08;只读&#xff09;, O_WRONLY&#xff08;只写&#xff09;, O_RDWR&#xff08;读写&#xff09;&#xff0c;当文件打开成…

HDU - 6621 K-th Closest Distance——主席树+二分

【题目描述】 HDU - 6621 K-th Closest Distance 【题目分析】 因为看到第kkk大的要求&#xff0c;刚开始的时候一直都在想怎么运用第kkk大来解决问题&#xff0c;但是后来看其他人的博客才发现并不需要用第k大&#xff0c;但是主席树维护权值线段树还是需要的&#xff0c;这…

链表相关的算法题大汇总 — 数据结构之链表奇思妙想

http://blog.csdn.net/lanxuezaipiao/article/details/22100021基本函数&#xff08;具体代码实现见后面&#xff09; 1&#xff0c;构造节点 //定义节点类型 struct Node { int value; Node*next; }; 2&#xff0c;分配节点 //之所以要分配节点原因是需要在分配函数中…

CodeForces - 372CWatching Fireworks is Fun+DP+单调队列优化

【题目描述】 CodeForces - 372CWatching Fireworks is Fun 题目的大概意思就是在一个编号为1…n的街道上现在按照时间顺序放烟花&#xff0c;每个烟花获得的幸福感为b−abs(a−x)b-abs(a-x)b−abs(a−x)&#xff0c;x为观看烟花的位置&#xff0c;为了提升我们的幸福感&#x…

双向链表的基本操作

1.双向链表的数据结构 typedef char DLinkType;typedef struct DLinkNode { DLinkType data; struct DLinkNode* next; struct DLinkNode* prev; }DLinkNode; 双向带头结点的链表有三个成员&#xff0c; 一个是数据&#xff0c; 一个是指针 next 指向当前结点的下一个结点&…

匿名管道

1.进程通信的目的 (1) 数据传输: 一个进程需要将它的数据传输给另一个进程     (2) 资源共享: 多个进程之间共享同样的资源     (3) 通知事件: 一个进程需要向另一个或一组进程发送消息, 通知它们发生了什么事情 2.管道 管道是一种进程之间通信的一种方式, 我们把从…

Currency Exchange——最短路Bellman-Ford算法

【题目描述】 Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several points specializing in the sam…

C++实现String类

http://blog.csdn.net/randyjiawenjie/article/details/6709539 C实现String类&#xff0c;还没有完成&#xff0c;待继续。 有以下注意的点&#xff1a; &#xff08;1&#xff09;赋值操作符返回的是一个MyString&&#xff0c;而重载的返回的是一个MyString。其中的原因…

POJ 3370 Halloween treats——鸽巢原理+思维

【题目描述】 POJ 3370 Halloween treats Description Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets on that day, no matter how many children call on him, so it may happen that a chi…

将信号量代码生成静态库以及动态库

1.信号量相关代码生成静态库 2.信号量相关代码生成动态库

Wormholes——Bellman-Ford判断负环

【题目描述】 While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of…

C++11 标准新特性:Defaulted 和 Deleted 函数

https://www.ibm.com/developerworks/cn/aix/library/1212_lufang_c11new/index.html Defaulted 函数 背景问题 C 的类有四类特殊成员函数&#xff0c;它们分别是&#xff1a;默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符。这些类的特殊成员函数负责创建、初始化、…

顺序表实现栈相关操作

1.栈的相关概念 栈是一种特殊的线性表, 其中只允许在固定的一端进行插入和删除元素.进行数据插入和删除的一端叫做栈顶, 另一端成为栈底. 不含任何元素的栈称为空栈, 栈又称为先进先出的线性表. 2. 顺序栈的结构 3. 顺序栈的具体操作 (1). 数据结构 typedef char SeqStackTyp…

MPI Maelstrom——Dijkstra

【题目描述】 BIT has recently taken delivery of their new supercomputer, a 32 processor Apollo Odyssey distributed shared memory machine with a hierarchical communication subsystem. Valentine McKee’s research advisor, Jack Swigert, has asked her to bench…

双向带环带头结点的链表实现栈

1. 数据结构 利用带头结点带环的结点实现栈的相关操作.因此, 每一个结点包括了一个前驱, 一个后继, 还有一个数据成员 typedef char DLinkStackType;typedef struct DLinkStack {DLinkStackType data;struct DLinkStack* next;struct DLinkStack* prev; }DLinkStack;2. 初始化…

Cow Contest——Floyed+连通性判断

【题目描述】 N (1 ≤ N ≤ 100) cows, conveniently numbered 1…N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors. The contest …

C++11 标准新特性:委派构造函数

https://www.ibm.com/developerworks/cn/rational/1508_chenjing_c11/index.html陈 晶2015 年 8 月 11 日发布WeiboGoogle用电子邮件发送本页面 1本文首先介绍了在委派构造函数提出之前类成员构造所面临的问题&#xff0c;再结合实例介绍了委派构造函数的用法&#xff0c;并说明…

顺序表实现队列

一. 队列相关概念 队列是只允许在一段进行插入元素, 在另一端进行删除元素的线性表,即只允许对队列进行尾插,头删的操作.队列具有先进先出, 后进后出的特性.          1.初始化 void SeqQueInit(SeqQue* q) {if(q NULL){return;//非法输入}q -> head 0;q -> …