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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

select、poll、epoll使用小结

發(fā)布時間:2023/11/30 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 select、poll、epoll使用小结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載:http://blog.csdn.net/kkxgx/article/details/7717125

Linux上可以使用不同的I/O模型,我們可以通過下圖了解常用的I/O模型:同步和異步模型,以及阻塞和非阻塞模型,本文主要分析其中的異步阻塞模型。


一、select使用

這個模型中配置的是非阻塞I/O,然后使用阻塞select系統(tǒng)調(diào)用來確定一個I/O描述符何時有操作。使用select調(diào)用可以為多個描述符提供通知,對于每個提示符,我們可以請求描述符的可寫,可讀以及是否發(fā)生錯誤。異步阻塞I/O的系統(tǒng)流程如下圖所示:


使用select常用的幾個函數(shù)如下:

[cpp]?view plaincopy
  • FD_ZERO(int?fd,?fd_set*?fds)???
  • FD_SET(int?fd,?fd_set*?fds)???
  • FD_ISSET(int?fd,?fd_set*?fds)???
  • FD_CLR(int?fd,?fd_set*?fds)???
  • int?select(int?nfds,?fd_set?*readfds,?fd_set?*writefds,?fd_set?*exceptfds,?struct?timeval?*timeout)???
  • fd_set類型可以簡單的理解為按bit位標記句柄的隊列。具體的置位、驗證可以使用FD_SET,FD_ISSET等宏實現(xiàn)。在select函數(shù)中,readfds、writefds和exceptfds同時作為輸入?yún)?shù)和輸出參數(shù),如果readfds標記了一個位置,則,select將檢測到該標記位可讀。timeout為設置的超時時間。

    下面我們來看如何使用select:

    [cpp]?view plaincopy
  • SOCKADDR_IN?addrSrv;??
  • int?reuse?=?1;??
  • SOCKET?sockSrv,connsock;??
  • SOCKADDR_IN?addrClient;??
  • pool?pool;??
  • int?len=sizeof(SOCKADDR);??
  • /*創(chuàng)建TCP*/??
  • sockSrv=socket(AF_INET,SOCK_STREAM,0);??
  • /*地址、端口的綁定*/??
  • ??
  • addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);??
  • addrSrv.sin_family=AF_INET;??
  • addrSrv.sin_port=htons(port);??
  • ??
  • if(bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))<0)??
  • {??
  • ????fprintf(stderr,"Failed?to?bind");??
  • ????return?;??
  • }??
  • ??
  • if(listen(sockSrv,5)<0)??
  • {??
  • ????fprintf(stderr,"Failed?to?listen?socket");??
  • ????return?;??
  • }??
  • setsockopt(sockSrv,SOL_SOCKET,SO_REUSEADDR,(const?char*)&reuse,sizeof(reuse));??
  • init_pool(sockSrv,&pool);??
  • while(1)??
  • {??
  • ????/*通過selete設置為異步模式*/??
  • ????pool.ready_set=pool.read_set;??
  • ????pool.nready=select(pool.maxfd+1,&pool.ready_set,NULL,NULL,NULL);??
  • ????if(FD_ISSET(sockSrv,&pool.ready_set))??
  • ????{??
  • ????????connsock=accept(sockSrv,(SOCKADDR?*)&addrClient,&len);??
  • ????????//loadDeal()/*連接處理*/??
  • ????????//printf("test\n");??
  • ????????add_client(connsock,&pool);//添加到連接池??
  • ????}??
  • ????/*檢查是否有事件發(fā)生*/??
  • ????check_client(&pool);??
  • }??
  • 上面是一個服務器代碼的關(guān)鍵部分,設置為異步的模式,然后接受到連接將其添加到連接池中。監(jiān)聽描述符上使用select,接受客戶端的連接請求,在check_client函數(shù)中,遍歷連接池中的描述符,檢查是否有事件發(fā)生。





    二、poll使用

    poll函數(shù)類似于select,但是其調(diào)用形式不同。poll不是為每個條件構(gòu)造一個描述符集,而是構(gòu)造一個pollfd結(jié)構(gòu)體數(shù)組,每個數(shù)組元素指定一個描述符標號及其所關(guān)心的條件。定義如下:

    [cpp]?view plaincopy
  • #include?<sys/poll.h>??
  • int?poll?(struct?pollfd?*fds,?unsigned?int?nfds,?int?timeout);??
  • struct?pollfd?{??
  • int?fd;?/*?file?descriptor?*/??
  • short?events;?/*?requested?events?to?watch?*/??
  • short?revents;?/*?returned?events?witnessed?*/??
  • };??
  • 每個結(jié)構(gòu)體的events域是由用戶來設置,告訴內(nèi)核我們關(guān)注的是什么,而revents域是返回時內(nèi)核設置的,以說明對該描述符發(fā)生了什么事件。這點與select不同,select修改其參數(shù)以指示哪一個描述符準備好了。在《unix環(huán)境高級編程》中有一張events取值的表,如下:

    POLLIN :可讀除高優(yōu)級外的數(shù)據(jù),不阻塞

    POLLRDNORM:可讀普通數(shù)據(jù),不阻塞

    POLLRDBAND:可讀O優(yōu)先數(shù)據(jù),不阻塞

    POLLPRI:可讀高優(yōu)先數(shù)據(jù),不阻塞

    POLLOUT :可寫普數(shù)據(jù),不阻塞

    POLLWRNORM:與POLLOUT相同

    POLLWRBAND:寫非0優(yōu)先數(shù)據(jù),不阻塞

    其次revents還有下面取值

    POLLERR :已出錯

    POLLHUP:已掛起,當以描述符被掛起后,就不能再寫向該描述符,但是仍可以從該描述符讀取到數(shù)據(jù)。

    POLLNVAL:此描述符并不引用一打開文件

    對poll函數(shù),nfds表示fds中的元素數(shù),timeout為超時設置,單位為毫秒若為0,表示不等待,為-1表示描述符中一個已經(jīng)準備好或捕捉到一個信號返回,大于0表示描述符準備好,或超時返回。函數(shù)返回值返回值若為0,表示沒有事件發(fā)生,-1表示錯誤,并設置errno,大于0表示有幾個描述符有事件。

    poll的使用和select基本類似。在此不再介紹。poll相對于是select的優(yōu)勢是監(jiān)聽的描述符數(shù)量沒有限制。

    三、epoll學習

    epoll有兩種模式,Edge Triggered(簡稱ET) 和 Level Triggered(簡稱LT).在采用這兩種模式時要注意的是,如果采用ET模式,那么僅當狀態(tài)發(fā)生變化時才會通知,而采用LT模式類似于原來的select/poll操作,只要還有沒有處理的事件就會一直通知.

    1)epoll數(shù)據(jù)結(jié)構(gòu)介紹:

    [cpp]?view plaincopy
  • typedef?union?epoll_data??
  • {??
  • ??void????????*ptr;??
  • ??int??????????fd;??
  • ??__uint32_t???u32;??
  • ??__uint64_t???u64;??
  • }?epoll_data_t;??
  • ??
  • struct?epoll_event??
  • {??
  • ??__uint32_t???events;?/*?Epoll?events?*/??
  • ??epoll_data_t?data;???/*?User?data?variable?*/??
  • };??
  • 常見的事件如下:

    EPOLLIN:表示對描述符的可以讀

    EPOLLOUT:表示對描述符的可以寫

    EPOLLPRI:表示對描述符的有緊急數(shù)據(jù)可以讀

    EPOLLERR:發(fā)生錯誤

    EPOLLHUP:掛起

    EPOLLET:邊緣觸發(fā)

    EPOLLONESHOT:一次性使用,當監(jiān)聽完這次事件之后,如果還需要繼續(xù)監(jiān)聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里

    2)函數(shù)介紹

    epoll的三個函數(shù)

    [cpp]?view plaincopy
  • int?epoll_creae(int?size);??
  • 功能:該函數(shù)生成一個epoll專用的文件描述符

    參數(shù):size為epoll上能關(guān)注的最大描述符數(shù)

    [cpp]?view plaincopy
  • int?epoll_ctl(int?epfd,?int?op,?int?fd,?struct?epoll_event?*event);??
  • 功能:用于控制某個epoll文件描述符時間,可以注冊、修改、刪除

    參數(shù):epfd由epoll_create生成的epoll專用描述符

    ? ? op操作:EPOLL_CTL_ADD 注冊 ? EPOLL_CTL_MOD修改 ?EPOLL_DEL刪除

    ? ? ? ? ? ? fd:關(guān)聯(lián)的文件描述符

    ? ? evnet告訴內(nèi)核要監(jiān)聽什么事件

    [cpp]?view plaincopy
  • int?epoll_wait(int?epfd,struct?epoll_event*events,int?maxevents,int?timeout);??
  • 功能:該函數(shù)等待i/o事件的發(fā)生。

    參數(shù):epfd要檢測的句柄

    ? ? ?events:用于回傳待處理時間的數(shù)組

    ? ? ?maxevents:告訴內(nèi)核這個events有多大,不能超過之前的size

    ? ? ?timeout:為超時時間

    使用方法參考:https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c


    epoll支持的FD上限是最大可以打開文件的數(shù)目(select面臨這樣的問題),IO效率不隨FD數(shù)目增加而線性下降(select、poll面臨的問題)使用mmap加速內(nèi)核與用戶空間的消息傳遞。現(xiàn)在libevent封裝了幾種的實現(xiàn),可以通過使用libevent來實現(xiàn)多路復用。


    ?本文參考:https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

    ? ?http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/index.html?ca=drs-

    ? ? ? ? ? ? ?http://www.ibm.com/developerworks/cn/linux/l-async/


    總結(jié)

    以上是生活随笔為你收集整理的select、poll、epoll使用小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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