生活随笔
收集整理的這篇文章主要介紹了
I/O多路转接之poll 函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://blog.csdn.net/li_ning_/article/details/52167224
poll
一、poll()函數:
這個函數是某些Unix系統提供的用于執行與select()函數同等功能的函數,自認為poll和select大同小異,下面是這個函數的聲明:
[cpp]?view plain
?copy #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描述符的情況;
結構如下:
[cpp]?view plain
?copy 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上的讀、寫、異常事件感興趣,就可以這樣做:
[cpp]?view plain
?copy struct?pollfd??fds;?? ?? fds[index].events=POLLIN?|?POLLOUT?|?POLLERR;??
當 poll()函數返回時,要判斷所檢測的socket描述符上發生的事件,可以這樣做:
[cpp]?view plain
?copy 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服務器的服務器程序
[cpp]?view plain
?copy #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);?? }??
賜教!
總結
以上是生活随笔為你收集整理的I/O多路转接之poll 函数的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。