I/O多路转接之poll

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了I/O多路转接之poll相关的知识,希望对你有一定的参考价值。

不同与select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现。

 

pollfd结构包含了要监视的event和发生的event,不再使select“参数-值”传递的方式。同时,pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 select函数一样,poll回后,需要轮询pollfd来获取就绪的描述符。


从上面看,selectpoll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事

实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描

述符数量的增长,其效率也会线性下降。

SYNOPSIS
      #include <poll.h>
 
      int poll(struct pollfd *fds, nfds_t nfds, int timeout);
 
      #define _GNU_SOURCE
      #include <poll.h>
 
      int ppoll(struct pollfd *fds, nfds_t nfds,
               const struct timespec *timeout,const sigset_t *sigmask);
 
DESCRIPTION
      poll()  performs a similar task toselect(2): it waits for one of a set
      of file descriptors to become ready to perform I/O.
 
      The set of file descriptors to be monitored is  specified in  the  fds
      argument, which is an array of nfds structures of the following form:
 
          struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
                short revents;    /* returned events */
          };
 
      The field fd contains a file descriptor for an open file.
 
      The  field  events is  an  input parameter, a bit mask specifying the
      events the application is interested in.
 
      The field revents is an output parameter, filled by the kernel with the
      events  that  actually occurred.   The  bits returned  in revents can
       include any of those specified in events, orone of the values POLLERR,
      POLLHUP,  or POLLNVAL.  (These three bits are meaningless in theevents
      field, and will be set in the revents field whenever the  corresponding
      condition is true.)
 
      If  none of the events requested(and no error) has occurred for any of
      the file descriptors, then poll()  blocks  until one  of  the events
      occurs.

tcp_server.c:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<netinet/in.h>
  4 #include<arpa/inet.h>
  5 #include<sys/socket.h>
  6 #include<sys/types.h>
  7 #include<unistd.h>
  8 #include<poll.h>
  9 #include<string.h>
 10 
 11 #define timeout 5000
 12 #define max_num 2
 13 #define back_log 5
 14 void usage(char* argv)
 15 {   
 16     printf("%s:[ip][port]\n",argv);
 17 }
 18 int start_up(char* ip,int port)
 19 {
 20     int sock=socket(AF_INET,SOCK_STREAM,0);
 21     if(sock<0)
 22     {
 23         perror("sock");
 24         exit(1);
 25     }
 26     struct sockaddr_in local;
 27     local.sin_family=AF_INET;
 28     local.sin_port=htons(port);
 29     local.sin_addr.s_addr=inet_addr(ip);
 30 
 31     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
 32     {
 33       perror("bind");
 34       exit(1);
 35     }
 36     if(listen(sock,back_log)<0)
 37     {
 38         perror("sock");
 39         exit(1);
 40     }
 41     return sock;
 42     
 43 }
 44 int main(int argc,char* argv[])
 45 {
 46     if(argc!=3)
 47     {
 48         usage(argv[0]);
 49         exit(1);
 50     }
 51     int port=atoi(argv[2]);
 52     char* ip=argv[1];
 53     int listen_sock=start_up(ip,port);
 54 
 55     struct sockaddr_in client;
 56     socklen_t len=sizeof(client);
 57     int new_sock=-1;
 58 
 59     int done=0;
 60     struct pollfd poll_set[max_num];
 61 
 62     int i=0;
 63     for(i=0;i<max_num;i++)
 64     {
 65         poll_set[i].fd=-1;
 66     }
 67     poll_set[0].fd=listen_sock;
 68     poll_set[0].events=POLLIN;
 69     poll_set[0].revents=0;
 70     while(!done)
 71     {
 72         switch(poll(poll_set,2,timeout))
 73         { 
 74             case 0:
 75                 printf("timeout\n");
 76                 break; 
 77             case -1:
 78                 perror("poll");
 79                 break;
 80             default:
 81                 { 
 82                  for(i=0;i<max_num;i++)
 83                  {                                //listen_sock
 84                      if(poll_set[i].fd==listen_sock&&poll_set[i].revents\ 
 85                              &POLLIN)
 86                      {
 87                          new_sock=accept(listen_sock,(struct sockaddr*) 88                                  &client,&len);
 89                          if(new_sock<0)
 90                          {
 91                              perror("accept");
 92                              continue;
 93                          }
 94                          printf("get connection->%d\n",new_sock);
 95                          for(i=0;i<max_num;i++)
 96                          {
 97                              if(poll_set[i].fd==-1)
 98                              {
 99                                  poll_set[i].fd=new_sock;
100                                  poll_set[i].events=POLLIN;
101                                  poll_set[i].revents=0;
102                              }
103                          }
104                      }
105                      else if(poll_set[i].revents&POLLIN)  //普通socket
106                      {
107                          char buf[1024];
108                          memset(buf,‘\0‘,sizeof(buf));
109                          ssize_t _s=read(poll_set[i].fd,buf,sizeof(buf)-1);
110                          if(_s>0)
111                          {
112                              buf[_s-1]=‘\0‘;
113                              printf("%s\n",buf);
114                          }
115                          else if(_s==0)
116                          {
117                              printf("client closed\n");
118                          }
119                          else
120                          {
121                              perror("read");
122                          }
123 
124                           
125                      }
126                      else 
127                         {}
128                        
129                  }
130                  break;
131                 }
132 
133         }
134     }
135     return 0;
136 }

tcp_client.c:

  1 
  2 #include<sys/socket.h>
  3 #include<sys/types.h>
  4 #include<unistd.h>
  5 #include<errno.h>
  6 #include<string.h>
  7 #include<arpa/inet.h>
  8 #include<netinet/in.h>
  9 #include<string.h>
 10 #include<stdlib.h>
 11 #include<stdio.h>
 12 
 13 
 14 void usage(char* proc)
 15 { 
 16   printf("Usage:%s[ip][port]\n",proc);
 17 }
 18 int main(int argc,char* argv[])
 19 {
 20     if(argc!=3)
 21     {
 22         usage(argv[0]);
 23         exit(1);
 24     }
 25 char* ip=argv[1];
 26 int port=atoi(argv[2]);
 27 
 28     //socket
 29     int sock=socket(AF_INET,SOCK_STREAM,0);
 30     if(sock<0)
 31     {
 32         perror("sock");
 33         exit(2);
 34     }
 35     struct sockaddr_in remote;
 36     remote.sin_family=AF_INET;
 37     remote.sin_port=htons(port);
 38     remote.sin_addr.s_addr=inet_addr(ip);
 39 
 40      int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));
 41      if(ret<0)
 42      {
 43        perror("coneect");
 44      }
 45 
 46      char buf[1024];
 47      while(1)
 48      {
 49          memset(buf,‘\0‘,sizeof(buf));
 50          read(0,buf,sizeof(buf)-1);
 51          ssize_t _s= write(sock,buf,sizeof(buf)-1);
 52          if(_s<0)
 53          {
 54              perror("write");
 55          }
 56      }
 57      return 0;
 58 }


server:

[[email protected] POLL]$ ./tcp_server 127.0.0.1 8080
get connection->4
nihao

woaini

timeout



client:


[[email protected] POLL]$ ./tcp_client 127.0.0.1 8080

nihao

woaini



poll与select不同在于描述型存储方式不同和参数类型不同。

1、结构体数组的管理:当每次有需要关心的描述符时,将其放入结构体中,每次有无效的描述符后,将其描述符置-1,下次poll函数会忽略它。当有新的描述符加入时,从头遍历结构体,将为-1的元素设为要关心的描述符事件状态。切记:当新的描述符加到结构体数组末尾时,即poll第二个参数。

2、每次调用poll后,结构体元素revents会存储就绪事件状态,当每次重新调用poll之前时,系统会自己设置其为0,重新监听关心事件(不需要用户重新置0)

3、poll中参数不是输入、输出型,因此timeout、struct pollfd* fds参数不需要重置,nfds看情况,而select函数是输入输出类型,每次调用前需重置。


本文出自 “liveyoung” 博客,转载请与作者联系!

以上是关于I/O多路转接之poll的主要内容,如果未能解决你的问题,请参考以下文章

I/O多路转接   ----   poll

I/O多路转接select/poll/epoll

Linux 高级IO

Linux 高级IO

I/O多路转接复用机制---select,poll,epoll

I/O多路转接模型 [select] [poll] [epoll]