多路复用I/O模型poll() 模型 代码实现

多路复用I/O模型poll() 模型 代码实现

poll()机制和select()机制是相似的,都是对多个描述符进行轮询的方式。

不同的是poll()没有描述符数目的限制。

是通过struct pollfd结构体,对每个描述符进行轮询的

struct pollfd fdarray

{

  int fd;    /*文件描述符*/

  short events; /*表示等待的事件*/

  short revents;/*表示返回事件即实际发生的事件*/

};

 每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回。合法的事件如下:

  POLLIN         有数据可读。

  POLLRDNORM       有普通数据可读。

  POLLRDBAND      有优先数据可读。

  POLLPRI         有紧迫数据可读。

  POLLOUT            写数据不会导致阻塞。

  POLLWRNORM       写普通数据不会导致阻塞。

  POLLWRBAND        写优先数据不会导致阻塞。

  POLLMSGSIGPOLL     消息可用。

  此外,revents域中还可能返回下列事件:
  POLLER     指定的文件描述符发生错误。

  POLLHUP   指定的文件描述符挂起事件。

  POLLNVAL  指定的文件描述符非法。

这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。

  使用poll()和select()不一样,你不需要显式地请求异常情况报告。
  POLLIN | POLLPRI等价于select()的读事件,POLLOUT |POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM |POLLRDBAND,而POLLOUT则等价于POLLWRNORM。例如,要同时监视一个文件描述符是否可读和可写,我们可以设置 events为POLLIN |POLLOUT。在poll返回时,我们可以检查revents中的标志,对应于文件描述符请求的events结构体。如果POLLIN事件被设置,则文件描述符可以被读取而不阻塞。如果POLLOUT被设置,则文件描述符可以写入而不导致阻塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描述符的读取和写入操作都会正常返回而不阻塞。

  timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数值表示无限超时,使poll()一直挂起直到一个指定事件发生;timeout为0指示poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。


  返回值和错误代码
  成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,poll()返回0;失败时,poll()返回-1,并设置errno为下列值之一:
  EBADF         一个或多个结构体中指定的文件描述符无效。

  EFAULTfds   指针指向的地址超出进程的地址空间。

  EINTR      请求的事件之前产生一个信号,调用可以重新发起。

  EINVALnfds  参数超出PLIMIT_NOFILE值。

  ENOMEM       可用内存不足,无法完成请求。

例子是从客户端发送信息,在服务器端显示并回射

data.h

 1 #ifndef DATA_H
 2 #define DATA_H
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <poll.h>
 6 #include <sys/types.h>
 7 #include <sys/stat.h>
 8 #include <stdlib.h>
 9 #include <errno.h>
10 #include <netinet/in.h>
11 #include <sys/socket.h>
12 #include <sys/select.h>
13 #include <arpa/inet.h>
14 #include <assert.h>
15 #include <unistd.h>
16 #define maxn 1100
17 #define MAXLINE 10
18 #define LISTEN 10
19 #define IP "127.0.0.1"
20 #define PORT 4578
21 #define BACKLOG 5
22 #define INFTIM -1
23 #endif

server.c

  1 #include "data.h"
  2 static void deal_message(struct pollfd *fd_array,int num);
  3 static void poll_accept(int sockfd);
  4 
  5 static int init()
  6 {
  7     struct sockaddr_in server_in;
  8     int sockfd;
  9     if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
 10     {
 11         fprintf(stderr,"socket fail,error :%s
",strerror(errno));
 12         return -1;
 13     }
 14     bzero(&server_in,sizeof(server_in));
 15     server_in.sin_family = AF_INET;
 16     server_in.sin_port = htons(PORT);
 17     inet_pton(AF_INET,IP,&server_in.sin_addr);
 18     if(bind(sockfd,(struct sockaddr*)&server_in,sizeof(struct sockaddr)) == -1)
 19     {
 20         fprintf(stderr,"bind fail,error:%s
",strerror(errno));
 21         return -1;
 22     }
 23     listen(sockfd,BACKLOG);
 24     return sockfd;
 25 }
 26 
 27 static void poll_accept(int sockfd)
 28 {
 29     struct pollfd fd_array[maxn];
 30     int afd;
 31     int pollfd;
 32     struct sockaddr_in client_in;
 33     bzero(&client_in,sizeof(client_in));
 34     int i = 0;
 35     fd_array[0].fd = sockfd;
 36     fd_array[0].events = POLLIN;
 37     for(i=1;i<maxn;i++)
 38     {
 39         fd_array[i].fd = -1;
 40     }
 41     int num = 0;
 42     int len = sizeof(client_in);
 43     for(;;)
 44     {
 45         pollfd = poll(fd_array,num+1,INFTIM); //无限等待
 46         if(pollfd == -1)
 47         {
 48             fprintf(stderr,"poll fail,error %s
",strerror(errno));
 49             return;
 50         }
 51         if(pollfd == 0)
 52         {
 53             continue;
 54         }
 55         if(fd_array[0].revents & POLLIN) //判断实际发生的事件是否为普通或优先级带数据可读
 56         {
 57             if((afd = accept(sockfd,(struct sockaddr*)&client_in,&len)) == -1)
 58             {
 59                 if(afd == EINTR)
 60                 {
 61                     continue;
 62                 }
 63                 else 
 64                 {
 65                     perror("accept error!");
 66                     return ;
 67                 }
 68             }
 69             
 70             fprintf(stdout,"accept a new client: %s:%d
", inet_ntoa(client_in.sin_addr),client_in.sin_port);
 71             for(i =1;i<maxn;i++)
 72             {
 73                 if(fd_array[i].fd < 0)
 74                 {
 75                     fd_array[i].fd = afd;
 76                     break;
 77                 }
 78             }
 79             if(i == maxn)
 80             {
 81                 printf("too many to server!
");
 82                 close(afd);
 83                 return ;
 84             }
 85             fd_array[i].events = POLLIN;
 86             if(i > num ) 
 87                 num = i;
 88             --pollfd;
 89         }
 90         deal_message(fd_array,num);
 91     }
 92 }
 93 
 94 static void deal_message(struct pollfd *fd_array,int num)
 95 {
 96     int i,n;
 97     char buf[maxn+20];
 98     char bbuf[maxn];
 99     memset(buf,'',sizeof(buf));
100     memset(bbuf,'',sizeof(bbuf));
101     for(i=1;i<=num;i++) //轮询的方式
102     {
103         if(fd_array[i].fd < 0)
104             continue;
105         if(fd_array[i].revents&POLLIN)
106         {
107             n = read(fd_array[i].fd,bbuf,maxn);
108             if(n == 0)
109             {
110                 close(fd_array[i].fd);
111                 fd_array[i].fd = -1;
112                 continue;
113             }
114             sprintf(buf,"client %d say %s",i,bbuf);
115             n += 15;
116             write(STDOUT_FILENO,buf,n);
117             write(fd_array[i].fd,buf,n);
118         }
119     }
120 }
121 int main()
122 {
123     int sockfd = init();
124     poll_accept(sockfd);
125     close(sockfd);
126     return 0;
127 }

client.c

 1 #include "data.h"
 2 
 3 static int  init()
 4 {
 5     int sockfd;
 6     struct sockaddr_in client_in;
 7     if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
 8     {
 9         fprintf(stderr,    "socket fail, errno %s
",strerror(errno));
10         return -1;
11     }
12     bzero(&client_in,sizeof(client_in));
13     client_in.sin_family = AF_INET;
14     client_in.sin_port = htons(PORT);
15     inet_pton(AF_INET,IP,&client_in.sin_addr);
16     connect(sockfd,(struct sockaddr*)&client_in,sizeof(client_in));
17     return sockfd;
18 }
19 static void poll_conn(int sockfd)
20 {
21     struct pollfd fdarray[2];
22     char buf[maxn];
23     int n;
24     fdarray[0].fd = sockfd;
25     fdarray[0].events = POLLIN;
26     fdarray[1].fd = STDIN_FILENO;
27     fdarray[1].events = POLLIN;
28     for(;;)
29     {
30         printf("please input message:
");
31         poll(fdarray,2,-1);
32         if(fdarray[0].revents & POLLIN)
33         {
34             n = read(sockfd,buf,maxn);
35             if(n == 0)
36             {
37                 fprintf(stderr,"server closed.
");
38                 close(sockfd);
39                 return;
40             }
41             write(STDOUT_FILENO,buf,n);
42             
43         }
44         if(fdarray[1].revents & POLLIN)
45         {
46             n = read(STDIN_FILENO,buf,maxn);
47             if(n == 0)
48             {
49                  shutdown(sockfd,SHUT_WR);
50                 continue;
51             }
52             write(sockfd,buf,n);
53         }
54     }
55 }
56 int main()
57 {
58     int sockfd = init();
59     poll_conn(sockfd);
60     close(sockfd);
61     return 0;
62 }

结果:

原文地址:https://www.cnblogs.com/chenyang920/p/5479580.html