日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

I/O多路转接之poll 函数

發(fā)布時(shí)間:2023/11/30 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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;??
  • ??
  • //檢測可讀TCP連接請求:??
  • if((fds[nIndex].revents?&?POLLIN)?==?POLLIN)??
  • {??
  • <span?style="white-space:pre">????</span>//接收數(shù)據(jù),調(diào)用accept()接收連接請求??
  • }??
  • ??
  • //檢測可寫:??
  • if((fds[nIndex].revents?&?POLLOUT)?==?POLLOUT)??
  • {??
  • <span?style="white-space:pre">????</span>//發(fā)送數(shù)據(jù)??
  • }??
  • ??
  • //檢測異常:??
  • 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)??//創(chuàng)建一個(gè)套接字,綁定,檢測服務(wù)器??
  • {??
  • ??//sock??
  • ??//1.創(chuàng)建套接字??
  • ??int?sock=socket(AF_INET,SOCK_STREAM,0);?????
  • ??if(sock<0)??
  • ??{??
  • ??????perror("sock");??
  • ??????exit(0);??
  • ??}??
  • ????
  • ??//2.填充本地?sockaddr_in?結(jié)構(gòu)體(設(shè)置本地的IP地址和端口)??
  • ??struct?sockaddr_in?local;?????????
  • ??local.sin_port=htons(port);??
  • ??local.sin_family=AF_INET;??
  • ??local.sin_addr.s_addr=inet_addr(ip);??
  • ??
  • ??//3.bind()綁定??
  • ??if(bind(sock,(struct?sockaddr*)&local,sizeof(local))<0)???
  • ??{??
  • ??????perror("bind");??
  • ??????exit(1);??
  • ??}??
  • ??//4.listen()監(jiān)聽?檢測服務(wù)器??
  • ??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];?//?用于poll函數(shù)第一個(gè)參數(shù)的數(shù)組,存放每次的文件描述符個(gè)數(shù)??
  •   if(?argc?!=?3?)??
  • ????{??
  •   ?????printf("Please?input?%s?<hostname>\n",?argv[0]);??
  • ?????exit(2);??
  • ????}??
  • ??
  • ????????int?listenfd=start_up(argv[1],argv[2]);??????//創(chuàng)建一個(gè)綁定了本地?ip?和端口號的套接字描述符??
  • ??????????
  •   ????client[0].fd?=?listenfd;?????????//將數(shù)組中的第一個(gè)元素設(shè)置成監(jiān)聽描述字??
  •   ????client[0].events?=?POLLIN;???????//將測試條件設(shè)置成普通或優(yōu)先級帶數(shù)據(jù)可讀(感興趣的事件讀、寫、出錯(cuò)),此處書中為POLLRDNORM,*/??
  • ????????client[0].revents?=?0;???????????//真正發(fā)生的事件??
  • ??
  •   ????for(i?=?1;i?<?OPEN_MAX;?++i)?????//數(shù)組中的其它元素將暫時(shí)設(shè)置成不可用??
  • ????????{??
  • ????????????client[i].fd?=?-1;??
  • ????????}??
  • ??????????
  •   ????maxi?=?0;??
  •  ??????while(1)??
  •   ????{??
  •   ???????nready?=?poll(client,?maxi+1,INFTIM);??????????//將進(jìn)程阻塞在poll上??
  •   ???????if(?client[0].revents?&?POLLIN)????????????????//先測試監(jiān)聽描述字??
  •   ???????{??
  • ????????????????connfd?=?accept(listenfd,(struct?sockaddr*)&servaddr,?&clilen);??
  • ??
  •   ????????????for(i?=?1;?i?<?OPEN_MAX;?++i)??
  • ????????????????{??
  • ????????????????????if(?client[i].fd?<?0?)??
  •   ????????????????{??
  •  ?????????????????????client[i].fd?=?connfd;??????//將新連接加入到測試數(shù)組中??
  •   ???????????????????client[i].events?=?POLLIN;??//POLLRDNORM;?測試條件普通數(shù)據(jù)可讀??
  •  ?????????????????????break;??
  •   ????????????????}??
  •   ??????????????if(?i?==?OPEN_MAX?)??
  •  ???????????????{??
  •   ??????????????????????printf("too?many?clients");?//連接的客戶端太多了,都達(dá)到最大值了??
  •  ???????????????????exit(1);??
  •   ??????????????}??
  • ??
  •   ??????????????if(?i?>?maxi?)??
  •   ??????????????????maxi?=?i;????????//maxi記錄的是數(shù)組元素的個(gè)數(shù)??
  • ??
  •   ??????????????if(?--nready?<=?0?)??
  •   ??????????????????continue;????????????//如果沒有可讀的描述符了,就重新監(jiān)聽連接??
  • ????????????????}??
  •   ????????}??
  • ??
  •   ????????for(i?=?1;?i?<=?maxi;?i++)??//測試除監(jiān)聽描述字以后的其它連接描述字??
  •   ????????{??
  • ????????????????if(?(sockfd?=?client[i].fd)?<?0)?//如果當(dāng)前描述字不可用,就測試下一個(gè)??
  •   ????????????????continue;??
  • ??
  •   ????????????if(client[i].revents?&?(POLLIN?|?POLLERR))//如果當(dāng)前描述字返回的是普通數(shù)據(jù)可讀或出錯(cuò)條件??
  •   ????????????{??
  •  ????????????????if(?(n?=?read(sockfd,?buf,?MAXLINE))?<?0)?//從套接口中讀數(shù)據(jù)??
  •   ???????????????{??
  •   ????????????????????if(?errno?==?ECONNRESET)?//如果連接斷開,就關(guān)閉連接,并設(shè)當(dāng)前描述符不可用??
  •   ????????????????????{??
  •   ???????????????????????close(sockfd);??
  •   ???????????????????????client[i].fd?=?-1;??
  •   ????????????????????}??
  •   ????????????????????else??
  •   ????????????????????????perror("read?error");??
  •   ????????????????}??
  •  ???????????????else?if(n?==?0)?//如果數(shù)據(jù)讀取完畢,關(guān)閉連接,設(shè)置當(dāng)前描述符不可用??
  •   ????????????????{??
  •   ????????????????????close(sockfd);??
  •   ????????????????????client[i].fd?=?-1;??
  •   ????????????????}??
  •   ????????????????else??
  •   ????????????????????write(sockfd,?buf,?n);?//打印數(shù)據(jù)??
  •   ?????????????if(--nready?<=?0)??
  •   ?????????????????break;??
  •   ????????????}??
  •   ????????}??
  •   ???}??
  •   ???exit(0);??
  •  }??
  • 賜教!

    總結(jié)

    以上是生活随笔為你收集整理的I/O多路转接之poll 函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。