青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

那誰的技術博客

感興趣領域:高性能服務器編程,存儲,算法,Linux內核
隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
數據加載中……

lighttpd1.4.18代碼分析(三)--網絡IO事件處理器的使用

本節(jié)是第二節(jié)lighttpd1.4.18代碼分析(二)--fdevents結構體解析的延續(xù),在閱讀本節(jié)內容之前,請先閱讀上一節(jié)內容.

上一節(jié)已經對lighttpd中的fdevent結構體進行了分析,前面提過,fdevent結構體是網絡IO事件處理器的"虛擬基類",提供了網絡IO事件處理器的公共成員,私有成員以及對外接口,這一節(jié)將對這個事件處理器的實現和使用進行解析.與這些相關的文件有這些:fdevent.h提供了fdevent結構體的定義, 在這個頭文件中聲明的函數可以看作是fdevent這個結構體對外暴露的接口, 也就是OO中所謂的類public函數, fdevent.c則是這些函數的實現,而以fdevent_為開頭的幾個C文件則是不同的網絡IO模型的實現,比如fdevent_select.c文件是select模型的實現.我不打算對各種類型的網絡IO模型做詳細的介紹,事實上,所有這里用到的網絡IO模型,我只用過select和epoll,所以我打算以select模型為例展開這里的討論,因為select是相對而言用的最多也是大多數人在學習多路復用IO的時候學到的第一個模型,即使在epoll橫行的今天,select模型仍然有著它的一席之地.

1)初始化
如何配置使用的是哪種網絡IO模型?在配置文件中有一項server.event-handler就是配置需要使用的網絡IO的,比如server.event-handler="select"就是選擇select, 其它的配置字符串參見前一節(jié)最開始提到的那些類型.服務器在初始化的時候讀取該配置項, 將網絡IO事件類型存放在結構體server的成員event_handler中.
接著, 在server.c的main函數中服務器調用fdevent_init(size_t maxfds, fdevent_handler_t type)初始化一個fdevents指針, 返回的結果存放在server結構體中的ev成員中.
在這個函數中, 根據type參數進行初始化, 生成具體各種不同類型的fdevents指針, 這些初始化的函數都是以init為后綴的, 而所有具體實現的文件名為
fdevent_***.c(如fdevent_select.c是select模型的實現), 對外暴露的僅僅是那個以init為后綴的函數, 而上面那些函數接口的實現全都是這些文件中
靜態(tài)函數, 很好的限制了它們的使用范圍, 做到了信息隱藏, 這些函數可以看作是類中的私有函數, 以select模型為例:
對外暴露的初始化函數是fdevent_select_init, 它在fdevent.h中聲明, 也就是說這個函數是對外暴露的, 而這個函數在fdevent_select.c被定義:
int fdevent_select_init(fdevents *ev) {
    ev
->type = FDEVENT_HANDLER_SELECT;
#define SET(x) \
    ev
->= fdevent_select_##x;

    SET(reset);
    SET(poll);

    SET(event_del);
    SET(event_add);

    SET(event_next_fdndx);
    SET(event_get_fd);
    SET(event_get_revent);

    
return 0;
}
查看fdevent_secelt.c文件,可以看到,名為fdevent_select_***的函數都是這個文件的靜態(tài)函數, 再從面向對象的觀點出發(fā),這些函數屬于采用select模型實現的fdevent的"私有函數", 如此做法, 很好的滿足了所謂的"信息隱藏".

2) 使用
在服務器創(chuàng)建一個socket fd并且進行監(jiān)聽后, 要將該fd注冊到fdevent中, 這樣才能使用使用這個事件處理機制.
在server.c文件的main函數中, 調用network_register_fdevents函數將所有監(jiān)聽的fd注冊到事件處理器中:
int network_register_fdevents(server *srv) {
    size_t i;

    
if (-1 == fdevent_reset(srv->ev)) {
        
return -1;
    }

    
/* register fdevents after reset */
    
for (i = 0; i < srv->srv_sockets.used; i++) {
        server_socket 
*srv_socket = srv->srv_sockets.ptr[i];

        fdevent_register(srv
->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
        fdevent_event_add(srv
->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
    }
    
return 0;
}


關鍵是在循環(huán)體中的兩個函數, fdevent_register的第三個參數是一個回調函數, 就是fdevents的成員fdarray中每個fdnode的成員handler:
int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
    fdnode 
*fdn;

    
// 分配一個fdnode指針
    fdn = fdnode_init();
   
    
// 保存回調函數
    fdn->handler = handler;
    
// 保存fd
    fdn->fd      = fd;
    
// 保存context 對server是server為socket指針, 對client是connection指針
    fdn->ctx     = ctx;

    
// 以fd為索引在fdarray中保存這個fdnode
    ev->fdarray[fd] = fdn;

    
return 0;
}

這里有一個小技巧, 函數中的倒數第二行, 以fd為索引保存fdnode, 因為這里的fdarray是一個數組, 因此這個方法可以以O(1)的速度找到與該fd相關的fdnode指針.但是, 因為0,1,2這三個fd已經提前預留給了標準輸入輸出錯誤這三個IO, 所以采用這樣的算法將會至少浪費三個fdnode指針.

現在, 可以對fdnode結構體中兩個成員進一步進行解析了:
    fdevent_handler handler;
    void *ctx;
其中, 如果該fd是服務器監(jiān)聽客戶端連接的fd, 那么handler = network_server_handle_fdevent(在network.c文件中), ctx保存的就是server指針;
如果該fd是accapt客戶端連接之后的fd, 那么handler = connection_handle_fdevent(在connections.c文件中), ctx保存的就是connection指針.

回過頭來看,在將服務器監(jiān)聽fd注冊到網絡IO事件處理器中之后, 這個處理器就要開始循環(huán)處理了, 在server.c中的main.c函數中是這個輪詢的主過程:
        // 輪詢FD
        if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
            
/* n is the number of events */
            
int revents;
            
int fd_ndx;

            fd_ndx 
= -1;
            
do {
                fdevent_handler handler;
                
void *context;
                handler_t r;

                
// 獲得處理這些事件的函數指針 fd等

                
// 獲得下一個fd在fdarray中的索引
                fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
                
// 獲得這個fd要處理的事件類型
                revents = fdevent_event_get_revent (srv->ev, fd_ndx);
                
// 獲取fd
                fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
                
// 獲取回調函數
                handler = fdevent_get_handler(srv->ev, fd);
                
// 獲取處理相關的context(對server是server_socket指針, 對client是connection指針)
                context = fdevent_get_context(srv->ev, fd);

                
/* connection_handle_fdevent needs a joblist_append */
                
// 進行處理
                switch (r = (*handler)(srv, context, revents)) {
                
case HANDLER_FINISHED:
                
case HANDLER_GO_ON:
                
case HANDLER_WAIT_FOR_EVENT:
                
case HANDLER_WAIT_FOR_FD:
                    
break;
                
case HANDLER_ERROR:
                    
/* should never happen */
                    SEGFAULT();
                    
break;
                
default:
                    log_error_write(srv, __FILE__, __LINE__, 
"d", r);
                    
break;
                }
            } 
while (--> 0);
簡單的說, 這個過程就是:首先調用poll函數指針獲取相關網絡IO被觸發(fā)的事件數, 保存在整型變量n中, 然后根據這個n值進行以下循環(huán), 每次處理完n值減一, 為0之后退出, 這個循環(huán)的大致過程是: 首先獲取下一個被觸發(fā)的網絡事件在fdnode數組中的索引, 接著根據該索引獲取相關的事件類型, fd, 回調函數, contex, ,接著根據這些調用回調函數(也就是我們上面提到的函數
network_server_handle_fdevent和connection_handle_fdevent),請注意, 在本節(jié)的最開始部分曾經提到過fdevent.h中聲明的函數都是對外暴露的fdevent結構體"public函數", 在上面這個輪詢的過程中使用的正是這些"public函數", 在這些"public函數"中再根據曾經初始化的函數指針進行調用, 實現了OO中所謂的"多態(tài)".

以上就是通過fdevent結構體實現的網絡IO處理器模型, 在這里體現如何使用C實現OO面向對象編程的種種常用技巧,不放在本節(jié)最后做一個總結:
1) fdevent結構體是一個虛擬基類, 其中的函數指針就是虛擬基類中的純虛函數, 由具體實現去初始化之.fdevent結構體中的對象為所有派生類的公共成員, 而用各個預編譯宏包圍的成員則是各個派生類的私有成員.

2) 在fdevent.h中聲明的函數可以理解為虛擬基類對外暴露的接口, 也就是public函數.

3) 各個具體的實現分別是各個實現C文件中的靜態(tài)函數, 也就是派生類的private函數.

如果閱讀到這里仍然對lighttpd中網絡IO處理器模型有疑問, 可以具體參看前面提到的fdevent.h/c文件, 以及以fdevent_為前綴的c文件.

posted on 2008-08-28 23:20 那誰 閱讀(4171) 評論(2)  編輯 收藏 引用 所屬分類: 網絡編程服務器設計Linux/Unixlighttpd

評論

# re: lighttpd1.4.18代碼分析(三)--網絡IO事件處理器的使用  回復  更多評論   

分析的不錯
2008-08-29 10:11 |

# re: lighttpd1.4.18代碼分析(三)--網絡IO事件處理器的使用[未登錄]  回復  更多評論   

謝謝博主的分析,寫的很到位
2008-08-29 18:50 | 鄒從杰
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99视频精品免费观看| 午夜精品电影| 欧美国产免费| 久久久久久69| 激情久久综合| 欧美日韩亚洲一区二区三区在线| 欧美顶级艳妇交换群宴| 久久理论片午夜琪琪电影网| 久久精品国产亚洲aⅴ| 亚洲欧美精品在线观看| 久久久www免费人成黑人精品| 久久蜜桃精品| 亚洲精品日韩一| 中文av字幕一区| 久久久91精品国产一区二区精品| 久久国产天堂福利天堂| 欧美激情一区二区久久久| 欧美婷婷久久| 在线观看视频免费一区二区三区| 亚洲精品在线视频观看| 亚洲综合首页| 久久久女女女女999久久| 欧美激情一区二区久久久| 国产亚洲电影| 亚洲三级电影在线观看 | 麻豆av福利av久久av| 最新国产成人在线观看| 羞羞答答国产精品www一本| 欧美粗暴jizz性欧美20| 在线看日韩欧美| 久久人人爽国产| 香蕉久久夜色精品国产使用方法| 亚洲一本视频| 夜夜嗨av一区二区三区免费区| 久久一区二区视频| 伊人夜夜躁av伊人久久| 久久免费少妇高潮久久精品99| 在线视频亚洲| 国产精品试看| 免费在线成人| 欧美黑人在线播放| 日韩视频不卡中文| 亚洲日韩成人| 国产精品三级视频| 欧美专区日韩视频| 亚洲欧美日韩精品久久久久| 国产精品国产a| 欧美在线观看你懂的| 香蕉成人伊视频在线观看| 影音先锋久久久| 欧美激情中文字幕乱码免费| 欧美经典一区二区三区| 亚洲一区二区在线看| 亚洲欧美日韩综合国产aⅴ| 国产日韩精品视频一区| 裸体一区二区三区| 欧美日韩中文字幕精品| 午夜精品一区二区三区在线 | 亚洲丰满少妇videoshd| 欧美国产日韩精品| 国产在线观看一区| 妖精成人www高清在线观看| 国产欧美日韩一区二区三区在线| 欧美成人在线免费视频| 国产精品自拍小视频| 99这里有精品| 性久久久久久久久久久久| 亚洲激情成人在线| 欧美一级理论性理论a| 国产精品99久久久久久久vr| 奶水喷射视频一区| 老司机午夜精品视频在线观看| 欧美精品网站| 亚洲精选中文字幕| 一本色道久久88综合亚洲精品ⅰ| 久久亚洲午夜电影| 嫩草国产精品入口| 亚洲娇小video精品| 久久久噜噜噜久噜久久| 欧美.www| 在线视频亚洲欧美| 欧美金8天国| 亚洲一区二区在线播放| 欧美中文字幕第一页| 新67194成人永久网站| 国产精品国产三级国产| 午夜精品久久久久久久蜜桃app | 国产精品毛片| 免费在线看成人av| 夜夜嗨av一区二区三区中文字幕| 性欧美xxxx大乳国产app| 亚洲国产日韩一区二区| 国产精品久久久一区二区三区| 亚洲视频一二三| 亚洲欧美在线磁力| 欧美chengren| 亚洲电影毛片| 久久九九免费| 亚洲一区二区精品在线| 在线观看亚洲视频| 国产一区二区三区免费观看| 欧美精品一卡| 你懂的视频欧美| 午夜精品视频在线| 一本色道久久| 亚洲伦理在线| 夜夜躁日日躁狠狠久久88av| 亚洲精品欧美专区| 一区二区欧美日韩| 一区二区三区免费网站| 日韩视频一区二区三区在线播放免费观看| 国产精品久久激情| 国产精品第一区| 国产综合色精品一区二区三区| 国产欧美日韩一区二区三区在线 | 中国成人黄色视屏| 亚洲欧美999| 午夜亚洲性色视频| 久久久www成人免费无遮挡大片| 欧美一区二区在线| 美女啪啪无遮挡免费久久网站| 久久先锋影音| 欧美视频不卡| 一区视频在线看| 亚洲最新视频在线| 亚洲尤物在线| 久久久综合网| 亚洲麻豆视频| 久久久久免费| 国产乱码精品一区二区三区不卡| 国产精品一区视频| 99视频在线观看一区三区| 久久久久久伊人| 亚洲视频1区| 欧美日韩一区二区三区在线观看免| 国产欧美一区二区精品性| 亚洲日本成人网| 免费的成人av| 久久爱www久久做| 国产精品久久波多野结衣| 91久久精品国产91久久| 久久这里只有精品视频首页| 欧美一区观看| 久久青草欧美一区二区三区| 亚洲一区视频| 日韩视频亚洲视频| 一区二区三区免费网站| 麻豆精品视频在线观看视频| 国产免费观看久久黄| 亚洲专区一区二区三区| 亚洲精品小视频| 欧美日韩国产小视频| 日韩一区二区精品视频| 亚洲免费观看在线观看| 欧美日韩亚洲视频| 午夜日韩福利| 猫咪成人在线观看| 亚洲精品视频在线看| 亚洲巨乳在线| 国产乱码精品一区二区三区不卡| 亚洲美女电影在线| 日韩午夜电影| 在线观看欧美日本| 亚洲国产精品第一区二区三区 | 亚洲男人第一av网站| 欧美亚洲综合在线| 亚洲伦伦在线| 亚洲专区在线视频| 91久久精品国产91久久| 亚洲嫩草精品久久| 一区二区三区高清在线观看| 亚洲欧美国产精品专区久久| 亚洲国产欧美日韩另类综合| 亚洲欧美日韩一区| 一本色道**综合亚洲精品蜜桃冫 | 欧美成人国产一区二区 | 国产日韩av一区二区| 亚洲狼人综合| 亚洲另类视频| 免费观看成人鲁鲁鲁鲁鲁视频| 欧美一区二区在线看| 欧美日韩国产高清| 国产综合18久久久久久| 亚洲第一视频网站| 在线观看亚洲精品视频| 久久精品亚洲精品| 午夜日韩在线| 国产精品久久久久久五月尺| 亚洲欧洲中文日韩久久av乱码| 亚洲国产导航| 欧美成人一区二区在线 | 在线成人h网| 免费毛片一区二区三区久久久| 六十路精品视频| 在线观看欧美黄色| 免费不卡在线观看| 亚洲高清不卡av| 亚洲一区一卡| 极品av少妇一区二区| 亚洲欧美视频一区|