生活随笔
收集整理的這篇文章主要介紹了
I/O多路转接之poll 函数
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
http://blog.csdn.net/li_ning_/article/details/52167224
poll
一、poll()函數(shù):
這個(gè)函數(shù)是某些Unix系統(tǒng)提供的用于執(zhí)行與select()函數(shù)同等功能的函數(shù),自認(rèn)為poll和select大同小異,下面是這個(gè)函數(shù)的聲明:
[cpp]?view plain
?copy #include?<poll.h>?? ?? int?poll(struct?pollfd?*fds,?nfds_t?nfds,?int?timeout);??
參數(shù):
1.第一個(gè)參數(shù):一個(gè)結(jié)構(gòu)數(shù)組,struct pollfd:
? ? ? ? fds:是一個(gè)struct pollfd結(jié)構(gòu)類型的數(shù)組,每個(gè)數(shù)組元素都是一個(gè)pollfd結(jié)構(gòu),用于指定測試某個(gè)給定描述字fd的條件。存放需要檢測其狀態(tài)的Socket描述符;每當(dāng)調(diào)用這個(gè)函數(shù)之后,系統(tǒng)不會清空這個(gè)數(shù)組,操作起來比較方便;特別是對于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點(diǎn)與select()函數(shù)不同,調(diào)用select()函數(shù)之后,select()函數(shù)會清空它所檢測的socket描述符集合,導(dǎo)致每次調(diào)用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數(shù)適合于只檢測一個(gè)socket描述符的情況,而poll()函數(shù)適合于大量socket描述符的情況;
結(jié)構(gòu)如下:
[cpp]?view plain
?copy struct?pollfd{?? int?fd;???????????? short?events;?????? short?revents;????? };??
events和revents是通過對代表各種事件的標(biāo)志進(jìn)行邏輯或運(yùn)算構(gòu)建而成的。events包括要監(jiān)視的事件(就是我需要關(guān)注的時(shí)間,是讀?是寫?還是出錯(cuò)?),poll用已經(jīng)發(fā)生的事件填充revents。poll函數(shù)通過在revents中設(shè)置標(biāo)志肌膚POLLHUP、POLLERR和POLLNVAL來反映相關(guān)條件的存在。不需要在events中對于這些標(biāo)志符相關(guān)的比特位進(jìn)行設(shè)置。如果fd小于0, 則events字段被忽略,而revents被置為0.標(biāo)準(zhǔn)中沒有說明如何處理文件結(jié)束。文件結(jié)束可以通過revents的標(biāo)識符POLLHUN或返回0字節(jié)的常規(guī)讀操作來傳達(dá)。即使POLLIN或POLLRDNORM指出還有數(shù)據(jù)要讀,POLLHUP也可能會被設(shè)置。因此,應(yīng)該在錯(cuò)誤檢驗(yàn)之前處理正常的讀操作。
poll函數(shù)的事件標(biāo)志符值:
| 常量 | 說明 |
| POLLIN | 普通或優(yōu)先級帶數(shù)據(jù)可讀 |
| POLLRDNORM | 普通數(shù)據(jù)可讀 |
| POLLRDBAND | 優(yōu)先級帶數(shù)據(jù)可讀 |
| POLLPRI | 高優(yōu)先級數(shù)據(jù)可讀 |
| POLLOUT | 普通數(shù)據(jù)可寫 |
| POLLWRNORM | 普通數(shù)據(jù)可寫 |
| POLLWRBAND | 優(yōu)先級帶數(shù)據(jù)可寫 |
| POLLERR | 發(fā)生錯(cuò)誤 |
| POLLHUP | 發(fā)生掛起 |
| POLLNVAL | 描述字不是一個(gè)打開的文件 |
? 注意:
? ? ? ? 1)后三個(gè)只能作為描述字的返回結(jié)果存儲在revents中,而不能作為測試條件用于events中。
2)第二個(gè)參數(shù)nfds:要監(jiān)視的描述符的數(shù)目。
3)最后一個(gè)參數(shù)timeout:是一個(gè)用毫秒表示的時(shí)間,是指定poll在返回前沒有接收事件時(shí)應(yīng)該等待的時(shí)間。如果? 它的值為-1,poll就永遠(yuǎn)都不會超時(shí)。如果整數(shù)值為32個(gè)比特,那么最大的超時(shí)周期大約是30分鐘。?
| timeout值 | 說明 |
| INFTIM | 永遠(yuǎn)等待 |
| 0 | 立即返回,不阻塞進(jìn)程 |
| >0 | 等待指定數(shù)目的毫秒數(shù) |
如果是對一個(gè)描述符上的多個(gè)事件感興趣的話,可以把這些常量標(biāo)記之間進(jìn)行按位或運(yùn)算就可以了;
比如:
對socket描述符fd上的讀、寫、異常事件感興趣,就可以這樣做:
[cpp]?view plain
?copy struct?pollfd??fds;?? ?? fds[index].events=POLLIN?|?POLLOUT?|?POLLERR;??
當(dāng) poll()函數(shù)返回時(shí),要判斷所檢測的socket描述符上發(fā)生的事件,可以這樣做:
[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>?? }??
二、實(shí)例TCP服務(wù)器的服務(wù)器程序
[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);?? }??
賜教!
總結(jié)
以上是生活随笔為你收集整理的I/O多路转接之poll 函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。