乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Epoll的ET模式與LT模式

       mrjbydd 2011-10-25

      Epoll的ET模式與LT模式   

      2008-07-09 14:35:30|  分類: 其它 |  標(biāo)簽: |字號 訂閱

      ET(Edge Triggered)與LT(Level Triggered)的主要區(qū)別可以從下面的例子看出
      eg:
      1. 標(biāo)示管道讀者的文件句柄注冊到epoll中;
      2. 管道寫者向管道中寫入2KB的數(shù)據(jù);
      3. 調(diào)用epoll_wait可以獲得管道讀者為已就緒的文件句柄;
      4. 管道讀者讀取1KB的數(shù)據(jù)
      5. 一次epoll_wait調(diào)用完成
      如果是ET模式,管道中剩余的1KB被掛起,再次調(diào)用epoll_wait,得不到管道讀者的文件句柄,除非有新的數(shù)據(jù)寫入管道。如果是LT模式,只要管道中有數(shù)據(jù)可讀,每次調(diào)用epoll_wait都會(huì)觸發(fā)。

      另一點(diǎn)區(qū)別就是設(shè)為ET模式的文件句柄必須是非阻塞的。
      三、 Epoll的實(shí)現(xiàn)
      Epoll的源文件在/usr/src/linux/fs/eventpoll.c,在module_init時(shí)注冊一個(gè)文件系統(tǒng)eventpoll_fs_type,對該文件系統(tǒng)提供兩種操作poll和release,所以epoll_create返回的文件句柄可以被poll、select或者被其它epoll epoll_wait。對epoll的操作主要通過三個(gè)系統(tǒng)調(diào)用實(shí)現(xiàn):
      1. sys_epoll_create
      2. sys_epoll_ctl
      3. sys_epoll_wait
      下面結(jié)合源碼講述這三個(gè)系統(tǒng)調(diào)用。
      1.1 long sys_epoll_create (int size)
      該系統(tǒng)調(diào)用主要分配文件句柄、inode以及file結(jié)構(gòu)。在linux-2.4.32內(nèi)核中,使用hash保存所有注冊到該epoll的文件句柄,在該系統(tǒng)調(diào)用中根據(jù)size大小分配hash的大小。具體為不小于size,但小于2*size的2的某次方。最小為2的9次方(512),最大為2的17次方(128 x 1024)。在linux-2.6.10內(nèi)核中,使用紅黑樹保存所有注冊到該epoll的文件句柄,size參數(shù)未使用。
      1.2 long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
      1. 注冊句柄 op = EPOLL_CTL_ADD
      注冊過程主要包括:
      A.將fd插入到hash(或rbtree)中,如果原來已經(jīng)存在返回-EEXIST,
      B.給fd注冊一個(gè)回調(diào)函數(shù),該函數(shù)會(huì)在fd有事件時(shí)調(diào)用,在該函數(shù)中將fd加入到epoll的就緒隊(duì)列中。
      C.檢查fd當(dāng)前是否已經(jīng)有期望的事件產(chǎn)生。如果有,將其加入到epoll的就緒隊(duì)列中,喚醒epoll_wait。

      2. 修改事件 op = EPOLL_CTL_MOD
      修改事件只是將新的事件替換舊的事件,然后檢查fd是否有期望的事件。如果有,將其加入到epoll的就緒隊(duì)列中,喚醒epoll_wait。

      3. 刪除句柄 op = EPOLL_CTL_DEL
      將fd從hash(rbtree)中清除。
      1.3 long sys_epoll_wait(int epfd, struct epoll_event *events, int maxevents,int timeout)
      如果epoll的就緒隊(duì)列為空,并且timeout非0,掛起當(dāng)前進(jìn)程,引起CPU調(diào)度。
      如果epoll的就緒隊(duì)列不空,遍歷就緒隊(duì)列。對隊(duì)列中的每一個(gè)節(jié)點(diǎn),獲取該文件已觸發(fā)的事件,判斷其中是否有我們期待的事件,如果有,將其對應(yīng)的epoll_event結(jié)構(gòu)copy到用戶events。

      revents = epi->file->f_op->poll(epi->file, NULL);
      epi->revents = revents & epi->event.events;
      if (epi->revents) {
      ……
      copy_to_user;
      ……
      }
      需要注意的是,在LT模式下,把符合條件的事件copy到用戶空間后,還會(huì)把對應(yīng)的文件重新掛接到就緒隊(duì)列。所以在LT模式下,如果一次epoll_wait某個(gè)socket沒有read/write完所有數(shù)據(jù),下次epoll_wait還會(huì)返回該socket句柄。
      四、 使用epoll的注意事項(xiàng)
      1. ET模式比LT模式高效,但比較難控制。
      2. 如果某個(gè)句柄期待的事件不變,不需要EPOLL_CTL_MOD,但每次讀寫后將該句柄modify一次有助于提高穩(wěn)定性,特別在ET模式。
      3. socket關(guān)閉后最好將該句柄從epoll中delete(EPOLL_CTL_DEL),雖然epoll自身有處理,但會(huì)使epoll的hash的節(jié)點(diǎn)數(shù)增多,影響搜索hash的速度。
      Q:網(wǎng)絡(luò)服務(wù)器的瓶頸在哪?
      A:IO效率。

      在大家苦苦的為在線人數(shù)的增長而導(dǎo)致的系統(tǒng)資源吃緊上的問題正在發(fā)愁的時(shí)候,Linux 2.6內(nèi)核中提供的System Epoll為我們提供了一套完美的解決方案。傳統(tǒng)的select以及poll的效率會(huì)因?yàn)樵诰€人數(shù)的線形遞增而導(dǎo)致呈二次乃至三次方的下降,這些直接導(dǎo)致了網(wǎng)絡(luò)服務(wù)器可以支持的人數(shù)有了個(gè)比較明顯的限制。

      自從Linux提供了/dev/epoll的設(shè)備以及后來2.6內(nèi)核中對/dev/epoll設(shè)備的訪問的封裝(System Epoll)之后,這種現(xiàn)象得到了大大的緩解,如果說幾個(gè)月前,大家還對epoll不熟悉,那么現(xiàn)在來說的話,epoll的應(yīng)用已經(jīng)得到了大范圍的普及。

      那么究竟如何來使用epoll呢?其實(shí)非常簡單。
      通過在包含一個(gè)頭文件#include 以及幾個(gè)簡單的API將可以大大的提高你的網(wǎng)絡(luò)服務(wù)器的支持人數(shù)。

      首先通過create_epoll(int maxfds)來創(chuàng)建一個(gè)epoll的句柄,其中maxfds為你epoll所支持的最大句柄數(shù)。這個(gè)函數(shù)會(huì)返回一個(gè)新的epoll句柄,之后的所有操作將通過這個(gè)句柄來進(jìn)行操作。在用完之后,記得用close()來關(guān)閉這個(gè)創(chuàng)建出來的epoll句柄。

      之后在你的網(wǎng)絡(luò)主循環(huán)里面,每一幀的調(diào)用epoll_wait(int epfd, epoll_event events, int max events, int timeout)來查詢所有的網(wǎng)絡(luò)接口,看哪一個(gè)可以讀,哪一個(gè)可以寫了。基本的語法為:
      nfds = epoll_wait(kdpfd, events, maxevents, -1);
      其中kdpfd為用epoll_create創(chuàng)建之后的句柄,events是一個(gè)epoll_event*的指針,當(dāng)epoll_wait這個(gè)函數(shù)操作成功之后,epoll_events里面將儲(chǔ)存所有的讀寫事件。max_events是當(dāng)前需要監(jiān)聽的所有socket句柄數(shù)。最后一個(gè)timeout是 epoll_wait的超時(shí),為0的時(shí)候表示馬上返回,為-1的時(shí)候表示一直等下去,直到有事件范圍,為任意正整數(shù)的時(shí)候表示等這么長的時(shí)間,如果一直沒有事件,則范圍。一般如果網(wǎng)絡(luò)主循環(huán)是單獨(dú)的線程的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個(gè)線程的話,則可以用0來保證主循環(huán)的效率。

      epoll_wait范圍之后應(yīng)該是一個(gè)循環(huán),遍利所有的事件:

      C/C++ code
      for(n = 0; n < nfds; ++n) { if(events[n].data.fd == listener) { //如果是主socket的事件的話,則表示有新連接進(jìn)入了,進(jìn)行新連接的處理。 client = accept(listener, (struct sockaddr *) &local, &addrlen); if(client < 0){ perror("accept"); continue; } setnonblocking(client); // 將新連接置于非阻塞模式 ev.events = EPOLLIN | EPOLLET; // 并且將新連接也加入EPOLL的監(jiān)聽隊(duì)列。 注意,這里的參數(shù)EPOLLIN | EPOLLET并沒有設(shè)置對寫socket的監(jiān)聽,如果有寫操作的話,這個(gè)時(shí)候epoll是不會(huì)返回事件的,如果要對寫操作也監(jiān)聽的話,應(yīng)該是EPOLLIN | EPOLLOUT | EPOLLET ev.data.fd = client; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) { // 設(shè)置好event之后,將這個(gè)新的event通過epoll_ctl加入到epoll的監(jiān)聽隊(duì)列里面,這里用EPOLL_CTL_ADD來加一個(gè)新的 epoll事件,通過EPOLL_CTL_DEL來減少一個(gè)epoll事件,通過EPOLL_CTL_MOD來改變一個(gè)事件的監(jiān)聽方式。 fprintf(stderr, "epoll set insertion error: fd=%d0, client); return -1; } } else // 如果不是主socket的事件的話,則代表是一個(gè)用戶socket的事件,則來處理這個(gè)用戶socket的事情,比如說read(fd,xxx)之類的,或者一些其他的處理。 do_use_fd(events[n].data.fd); }

      對,epoll的操作就這么簡單,總共不過4個(gè)API:epoll_create, epoll_ctl, epoll_wait和close。
      如果您對epoll的效率還不太了解,請參考我之前關(guān)于網(wǎng)絡(luò)游戲的網(wǎng)絡(luò)編程等相關(guān)的文章。

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多