• 多路复用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 }

    结果:

  • 相关阅读:
    后端程序员之路 28、一个轻量级HTTP Server的实现
    后端程序员之路 27、LogStash
    后端程序员之路 26、CAP理论
    后端程序员之路 25、Redis Cluster
    后端程序员之路 24、Redis hiredis
    后端程序员之路 23、一个c++的api framework
    后端程序员之路 22、RESTful API
    后端程序员之路 21、一个cgi的c++封装
    后端程序员之路 20、python复习
    flask框架的学习
  • 原文地址:https://www.cnblogs.com/chenyang920/p/5479580.html
Copyright © 2020-2023  润新知