1. 函数

wKiom1dzJNCg5hGZAAAXxJzCuJo233.png


a. 参数:

(1)fds:是一个struct pollfd结构类型的指针,指向用于存放需要检测状态的Socket描述符;

每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;

wKiom1d0a2ywCYtFAAAS83He4Qs347.png

  1. fd:表示所要关心的文件描述符;

  2. events:表示该文件描述符所关心的事件,这是一个输入型参数,要告诉操作系统这个文件描述符对应的事件所关心的操作事件是什么,比如读或写;

  3. revents:表示当poll返回时告诉用户什么操作事件是就绪的,比如如果POLLIN是就绪的,那么返回时revent的值就是POLLIN,告诉用户fd事件的POLLIN是就绪的;是一个输出型参数。


(2)nfds:标记指针fds所指向的结构体元素的总数量;


(3)timeout:poll函数调用阻塞的时间,单位:毫秒。(和select的一样)

如果参数timeout设为:

  1. INFTIM:select将一直被阻塞,直到某个文件描述符上发生了事件。

  2. 0:select将以非阻塞方式等,即检测描述符集的状态后立即返回,并不等待外部事件的发生。

  3. 大于0的值:poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果在指定的时间段里没有事件发生,select将超时返回0。


c. 返回值
(1)成功:则返回fds指针所指向的内容中准备好的读、写或出错状态的那些socket描述符的总数量(返回值>0);
(2)poll函数调用失败:返回-1,同时会自动设置全局变量errno;;
(3)超过timeout时间,返回0。(没有任何socket描述符准备好读、写,或出错)


2. poll和select对比

(1)不同:

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

  2. pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式。

  3. pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 

(2)相同:

  1. 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。

  2. 从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。


3.代码实现

//poll_server.c
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 #include
 10 
 11 #define _BACKLOG_ 5
 12 #define _NUM_ 10
 13 
 14 static void usage(const char* proc)
 15 {
 16     printf("usage:%s [ip]  [port]\n",proc);
 17 }
 18 static int startup(char* ip,int port)
 19 {
 20     assert(ip);
 21     //
 22     int sock=socket(AF_INET,SOCK_STREAM,0);
 23     if(sock<0)
 24     {
 25         perror("socket");
 26         exit(1);
 27     }
 28     //
 29     struct sockaddr_in local;
 30     local.sin_family=AF_INET;
 31     local.sin_port=htons(port);
 32     local.sin_addr.s_addr=inet_addr(ip);
 33     //
 34     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
 35     {
 36         perror("bind");
 37         exit(2);
 38     }
 39     if(listen(sock,_BACKLOG_)<0)
 40     {
 41         perror("listen");
 42         exit(3);
 43     }
 44     return sock;
 45 }
 46 int main(int argc,char* argv[])
 47 {
 48     if(argc!=3)
 49     {
 50         usage(argv[0]);
 51         exit(1);
 52     }
 53     char* ip=argv[1];
 54     int port=atoi(argv[2]);
 55 
 56     int listen_sock=startup(ip,port);
 57 
 58     struct sockaddr_in client;
 59     socklen_t len=sizeof(client);
 60 
 61     struct pollfd fds[_NUM_];
 62     int max_fd=1;//int max_fd=fds[0].fd
 63     int _timeout=5000;
 64     fds[0].fd=listen_sock;//why locate
 65     fds[0].events=POLLIN;
 66     fds[0].revents=0;
 67 
 68     size_t i=1;
 69     for(;i<_NUM_;i++)
 70     {
 71         fds[i].fd=-1;
 72         fds[i].events=0;
 73         fds[i].revents=0;
 74     }
 75     while(1)
 76     {
 77         switch(poll(fds,max_fd,_timeout))
 78         {
 79             case -1:
 80                 perror("poll");
 81                 break;
 82             case 0:
 83                 printf("timeout...\n");
 84                 break;
 85             default:
 86                 {
 87                     i=0;
 88                     for(;i<_NUM_;++i)
 89                     {
 90                         if((fds[i].fd==listen_sock)&&(fds[i].revents==POLLIN    ))
 91                         {
 92                             int new_sock=accept(listen_sock,(struct sockaddr    *)&client,&len);
 93                             if(new_sock<0)
 94                             {
 95                                 perror("accept");
 96                                 continue;
 97                             }
 98                             printf("get a new connect...%d\n",new_sock);
 99                             for(i=0;i<_NUM_;i++)
100                             {
101                                 if(fds[i].fd==-1)
102                                 {
103                                     fds[i].fd=new_sock;
104                                     fds[i].events=POLLIN;
105                                     max_fd++;
106                                     break;
107                                 }
108                             }
109                             if(i==_NUM_)
110                             {
111                                 close(new_sock);
112                             }
113                         }
114                         else if((fds[i].fd>0)&&(fds[i].revents==POLLIN))
115                         {
116                             char buf[1024];
117                             ssize_t _s=read(fds[i].fd,buf,sizeof(buf)-1);
118                             if(_s>0)
119                             {
120                                 //read sucess
121                                 buf[_s]='\0';
122                                 printf("client:%s\n",buf);
123                             }
124                             else if(_s==0)
125                             {
126                                 //client shutdown
127                                 printf("client shutdown...\n");
128                                 //
129                                 struct pollfd tmp=fds[i];
130                                 fds[i]=fds[max_fd-1];
131                                 fds[max_fd-1]=tmp;
132                                 //
133                                 close(fds[max_fd-1].fd);
134                                 //
135 
136                                 fds[max_fd-1].fd=-1;
137                                 fds[max_fd-1].events=0;
138                                 fds[max_fd-1].revents=0;
139                                 //easy ignore
140                                 --max_fd;
141                             }
142                             else
143                             {
144                                 perror("read");
145                             }
146                         }
147                         //normal socket
148                         else
149                         {}
150                     }
151                 }
152                 break;
153         }
154     }
155     return 0;
156 }

//poll_client.c
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 
 10 void usage(const char* proc)
 11 {   
 12     printf("%s [ip] [port]\n",proc);
 13     exit(1);
 14 }
 15 int main(int argc,char* argv[])
 16 {
 17     if(argc!=3)
 18     {
 19         usage(argv[0]);
 20         exit(1);
 21     }
 22     int server_ip=inet_addr(argv[1]);
 23     int server_port=atoi(argv[2]);
 24 
 25     int client_sock=socket(AF_INET,SOCK_STREAM,0);
 26     if(client_sock<0)
 27     {
 28         perror("socket");
 29         exit(2);
 30     }
 31     struct sockaddr_in server;
 32     server.sin_family=AF_INET;
 33     server.sin_addr.s_addr=server_ip;
 34     server.sin_port=htons(server_port);
 35 
 36     if(connect(client_sock,(struct sockaddr*)&server,sizeof(server))<0)
 37     {
 38         perror("connect");
 39         exit(3);
 40     }
 41     char buf[1024];
 42     while(1)
 43     {
 44         memset(buf,'\0',sizeof(buf));
 45         printf("Please Input: ");
 46         fflush(stdout);
 47         fgets(buf,sizeof(buf)-1,stdin);
 48         if(send(client_sock,buf,sizeof(buf)-1,0)<0)
 49         {
 50             perror("send");
 51             continue;
 52         }
 53         ssize_t _size=recv(client_sock,buf,sizeof(buf)-1,0);
 54         if(_size>0)
 55         {
 56             buf[_size]='\0';
 57             printf("server receive:%s\n",buf);
 58         }
 59     }
 60     return 0;
 61 }
 
 //makefile
  1 .PHONY:all
  2 all:poll_server poll_client
  3 poll_server:poll_server.c
  4     gcc -o $@ $^
  5 poll_client:poll_client.c
  6     gcc -o $@ $^
  7 .PHONY:clean
  8 clean:
  9     rm -f poll_server poll_client
  
  //start.sh
  1 #!/bin/bash
  2 
  3 service iptables stop
  4 ./poll_server 192.168.163.128 8080

运行结果:

I/O多路转接之poll——基于TCP协议_第1张图片