1. 函數
a. 參數:
(1)fds:是一個struct pollfd結構類型的指針,指向用於存放需要檢測狀態的Socket描述符;
每當調用這個函數之後,系統不會清空這個數組,操作起來比較方便;特別是對於socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點與select()函數不同,調用select()函數之後,select()函數會清空它所檢測的socket描述符集合,導致每次調用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數適合於只檢測一個socket描述符的情況,而poll()函數適合於大量socket描述符的情況;
fd:表示所要關心的文件描述符;
events:表示該文件描述符所關心的事件,這是一個輸入型參數,要告訴操作系統這個文件描述符對應的事件所關心的操作事件是什麼,比如讀或寫;
revents:表示當poll返回時告訴用戶什麼操作事件是就緒的,比如如果POLLIN是就緒的,那麼返回時revent的值就是POLLIN,告訴用戶fd事件的POLLIN是就緒的;是一個輸出型參數。
(2)nfds:標記指針fds所指向的結構體元素的總數量;
(3)timeout:poll函數調用阻塞的時間,單位:毫秒。(和select的一樣)
如果參數timeout設爲:
INFTIM:select將一直被阻塞,直到某個文件描述符上發生了事件。
0:select將以非阻塞方式等,即檢測描述符集的狀態後立即返回,並不等待外部事件的發生。
大於0的值:poll()函數會阻塞timeout所指定的毫秒時間長度之後返回,如果在指定的時間段裏沒有事件發生,select將超時返回0。
c. 返回值
(1)成功:則返回fds指針所指向的內容中準備好的讀、寫或出錯狀態的那些socket描述符的總數量(返回值>0);
(2)poll函數調用失敗:返回-1,同時會自動設置全局變量errno;;
(3)超過timeout時間,返回0。(沒有任何socket描述符準備好讀、寫,或出錯)
2. poll和select對比
(1)不同:
select使用三個位圖來表示三個fdset的方式,poll使用一個 pollfd的指針實現。
pollfd結構包含了要監視的event和發生的event,不再使用select“參數-值”傳遞的方式。
pollfd並沒有最大數量限制(但是數量過大後性能也是會下降)。
(2)相同:
和select函數一樣,poll返回後,需要輪詢pollfd來獲取就緒的描述符。
從上面看,select和poll都需要在返回後,通過遍歷文件描述符來獲取已經就緒的socket。事實上,同時連接的大量客戶端在一時刻可能只有很少的處於就緒狀態,因此隨着監視的描述符數量的增長,其效率也會線性下降。
3.代碼實現
//poll_server.c 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<assert.h> 4 #include<poll.h> 5 #include<unistd.h> 6 #include<sys/socket.h> 7 #include<sys/types.h> 8 #include<arpa/inet.h> 9 #include<netinet/in.h> 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<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/types.h> 5 #include<sys/socket.h> 6 #include<netinet/in.h> 7 #include<arpa/inet.h> 8 #include<unistd.h> 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
運行結果: