标签:i/o多路转接之poll
不同与select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现。
pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式。同时,pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的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:
[admin@localhost POLL]$ ./tcp_server 127.0.0.1 8080 get connection->4 nihao woaini timeout
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” 博客,转载请与作者联系!
标签:i/o多路转接之poll
原文地址:http://youngyoungla.blog.51cto.com/10697042/1784065