I/O多路转接之poll

来源:互联网 发布:mac电脑激活时间查询 编辑:程序博客网 时间:2024/05/17 00:08

不同与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)  //普通socket106                      {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                          else120                          {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:

[admin@localhost POLL]$ ./tcp_server 127.0.0.1 8080get connection->4nihaowoainitimeout



client:


[admin@localhost 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” 博客,转载请与作者联系!

0 0