http://blog.csdn.net/li_ning_/article/details/52167224
poll
一、poll()函數:
這個函數是某些Unix系統提供的用于執行與select()函數同等功能的函數,自認為poll和select大同小異,下面是這個函數的聲明:
- #include?<poll.h>??
- ??
- int?poll(struct?pollfd?*fds,?nfds_t?nfds,?int?timeout);??
參數:
1.第一個參數:一個結構數組,struct pollfd:
? ? ? ? fds:是一個struct pollfd結構類型的數組,每個數組元素都是一個pollfd結構,用于指定測試某個給定描述字fd的條件。存放需要檢測其狀態的Socket描述符;每當調用這個函數之后,系統不會清空這個數組,操作起來比較方便;特別是對于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點與select()函數不同,調用select()函數之后,select()函數會清空它所檢測的socket描述符集合,導致每次調用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數適合于只檢測一個socket描述符的情況,而poll()函數適合于大量socket描述符的情況;
結構如下:
- struct?pollfd{??
- int?fd;????????????
- short?events;??????
- short?revents;?????
- };??
events和revents是通過對代表各種事件的標志進行邏輯或運算構建而成的。events包括要監視的事件(就是我需要關注的時間,是讀?是寫?還是出錯?),poll用已經發生的事件填充revents。poll函數通過在revents中設置標志肌膚POLLHUP、POLLERR和POLLNVAL來反映相關條件的存在。不需要在events中對于這些標志符相關的比特位進行設置。如果fd小于0, 則events字段被忽略,而revents被置為0.標準中沒有說明如何處理文件結束。文件結束可以通過revents的標識符POLLHUN或返回0字節的常規讀操作來傳達。即使POLLIN或POLLRDNORM指出還有數據要讀,POLLHUP也可能會被設置。因此,應該在錯誤檢驗之前處理正常的讀操作。
poll函數的事件標志符值:
常量 | 說明 |
POLLIN | 普通或優先級帶數據可讀 |
POLLRDNORM | 普通數據可讀 |
POLLRDBAND | 優先級帶數據可讀 |
POLLPRI | 高優先級數據可讀 |
POLLOUT | 普通數據可寫 |
POLLWRNORM | 普通數據可寫 |
POLLWRBAND | 優先級帶數據可寫 |
POLLERR | 發生錯誤 |
POLLHUP | 發生掛起 |
POLLNVAL | 描述字不是一個打開的文件 |
? 注意:
? ? ? ? 1)后三個只能作為描述字的返回結果存儲在revents中,而不能作為測試條件用于events中。
2)第二個參數nfds:要監視的描述符的數目。
3)最后一個參數timeout:是一個用毫秒表示的時間,是指定poll在返回前沒有接收事件時應該等待的時間。如果? 它的值為-1,poll就永遠都不會超時。如果整數值為32個比特,那么最大的超時周期大約是30分鐘。?
timeout值 | 說明 |
INFTIM | 永遠等待 |
0 | 立即返回,不阻塞進程 |
>0 | 等待指定數目的毫秒數 |
如果是對一個描述符上的多個事件感興趣的話,可以把這些常量標記之間進行按位或運算就可以了;
比如:
對socket描述符fd上的讀、寫、異常事件感興趣,就可以這樣做:
- struct?pollfd??fds;??
- ??
- fds[index].events=POLLIN?|?POLLOUT?|?POLLERR;??
當 poll()函數返回時,要判斷所檢測的socket描述符上發生的事件,可以這樣做:
- struct?pollfd??fds;??
- ??
- ??
- if((fds[nIndex].revents?&?POLLIN)?==?POLLIN)??
- {??
- <span?style="white-space:pre">????</span>??
- }??
- ??
- ??
- if((fds[nIndex].revents?&?POLLOUT)?==?POLLOUT)??
- {??
- <span?style="white-space:pre">????</span>??
- }??
- ??
- ??
- if((fds[nIndex].revents?&?POLLERR)?==?POLLERR)??
- {??
- <span?style="white-space:pre">????</span>??
- }??
二、實例TCP服務器的服務器程序
- #include?<stdio.h>??
- #include?<stdlib.h>??
- #include?<unistd.h>??
- #include?<sys/socket.h>??
- #include?<sys/types.h>??
- #include?<netinet/in.h>??
- #include?<netdb.h> ??
- #include?<string.h>??
- #include?<errno.h>??
- #include?<poll.h>???//for?poll??
- ??
- #define?LISTENQ?1024??
- #define?MAXLINE?1024??
- #define?OPEN_MAX?50000??
- ??
- #ifndef?INFTIM???
- #define?INFTIM?-1???
- #endif???????????????
- ??
- int?start_up(char*?ip,int?port)????
- {??
- ????
- ????
- ??int?sock=socket(AF_INET,SOCK_STREAM,0);?????
- ??if(sock<0)??
- ??{??
- ??????perror("sock");??
- ??????exit(0);??
- ??}??
- ????
- ????
- ??struct?sockaddr_in?local;?????????
- ??local.sin_port=htons(port);??
- ??local.sin_family=AF_INET;??
- ??local.sin_addr.s_addr=inet_addr(ip);??
- ??
- ????
- ??if(bind(sock,(struct?sockaddr*)&local,sizeof(local))<0)???
- ??{??
- ??????perror("bind");??
- ??????exit(1);??
- ??}??
- ????
- ??if(listen(sock,back_log)<0)??
- ??{??
- ??????perror("sock");??
- ??????exit(1);??
- ??}??
- ??return?sock;??????
- }??
- ??????
- int?main(int?argc,?char?*argv[])??
- {??
- int?i,?maxi,?connfd,?sockfd;??
- int?nready;??
- ssize_t?n;??
- socklen_t?clilen;??
- ??
- struct?sockaddr_in?servaddr;??
- ????socklen_t?len=sizeof(servaddr);???
- ??
- ??char?buf[BUFSIZ];??
- ????struct?pollfd?client[OPEN_MAX];???
- if(?argc?!=?3?)??
- ????{??
- ?????printf("Please?input?%s?<hostname>\n",?argv[0]);??
- ?????exit(2);??
- ????}??
- ??
- ????????int?listenfd=start_up(argv[1],argv[2]);????????
- ??????????
- ????client[0].fd?=?listenfd;???????????
- ????client[0].events?=?POLLIN;?????????
- ????????client[0].revents?=?0;?????????????
- ??
- ????for(i?=?1;i?<?OPEN_MAX;?++i)???????
- ????????{??
- ????????????client[i].fd?=?-1;??
- ????????}??
- ??????????
- ????maxi?=?0;??
- ??????while(1)??
- ????{??
- ???????nready?=?poll(client,?maxi+1,INFTIM);????????????
- ???????if(?client[0].revents?&?POLLIN)??????????????????
- ???????{??
- ????????????????connfd?=?accept(listenfd,(struct?sockaddr*)&servaddr,?&clilen);??
- ??
- ????????????for(i?=?1;?i?<?OPEN_MAX;?++i)??
- ????????????????{??
- ????????????????????if(?client[i].fd?<?0?)??
- ????????????????{??
- ?????????????????????client[i].fd?=?connfd;????????
- ???????????????????client[i].events?=?POLLIN;????
- ?????????????????????break;??
- ????????????????}??
- ??????????????if(?i?==?OPEN_MAX?)??
- ???????????????{??
- ??????????????????????printf("too?many?clients");???
- ???????????????????exit(1);??
- ??????????????}??
- ??
- ??????????????if(?i?>?maxi?)??
- ??????????????????maxi?=?i;??????????
- ??
- ??????????????if(?--nready?<=?0?)??
- ??????????????????continue;??????????????
- ????????????????}??
- ????????}??
- ??
- ????????for(i?=?1;?i?<=?maxi;?i++)????
- ????????{??
- ????????????????if(?(sockfd?=?client[i].fd)?<?0)???
- ????????????????continue;??
- ??
- ????????????if(client[i].revents?&?(POLLIN?|?POLLERR))??
- ????????????{??
- ????????????????if(?(n?=?read(sockfd,?buf,?MAXLINE))?<?0)???
- ???????????????{??
- ????????????????????if(?errno?==?ECONNRESET)???
- ????????????????????{??
- ???????????????????????close(sockfd);??
- ???????????????????????client[i].fd?=?-1;??
- ????????????????????}??
- ????????????????????else??
- ????????????????????????perror("read?error");??
- ????????????????}??
- ???????????????else?if(n?==?0)???
- ????????????????{??
- ????????????????????close(sockfd);??
- ????????????????????client[i].fd?=?-1;??
- ????????????????}??
- ????????????????else??
- ????????????????????write(sockfd,?buf,?n);???
- ?????????????if(--nready?<=?0)??
- ?????????????????break;??
- ????????????}??
- ????????}??
- ???}??
- ???exit(0);??
- }??
賜教!