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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Lighttpd源码分析之状态机与插件

發布時間:2025/3/21 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Lighttpd源码分析之状态机与插件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Lighttpd啟動時完成了一系列初始化操作后,就進入了一個包含11個狀態的有限狀態機中。

每個連接都是一個connection實例(con),狀態的切換取決于con->state。

lighttpd經過初步處理后將con的基本信息初始化,而插件對事件的處理就是針對con進行的,它拿到con后按照業務需要進行相應處理,然后再交還給lighttpd,lighttpd根據con中的信息完成響應。

狀態定義如下:

[cpp] view plain copy
  • typedef?enum??
  • {??
  • ????CON_STATE_CONNECT,?????????????//connect?連接開始??
  • ?????CON_STATE_REQUEST_START,?????//reqstart?開始讀取請求??
  • ?????CON_STATE_READ,?????????????//read?讀取并解析請求??
  • ?????CON_STATE_REQUEST_END,?????????//reqend?讀取請求結束??
  • ?????CON_STATE_READ_POST,?????????//readpost?讀取post數據??
  • ?????CON_STATE_HANDLE_REQUEST,?????//handelreq?處理請求??
  • ????CON_STATE_RESPONSE_START,?????//respstart?開始回復??
  • ????CON_STATE_WRITE,?????????????//write?回復寫數據??
  • ????CON_STATE_RESPONSE_END,?????//respend?回復結束??
  • ????CON_STATE_ERROR,?????????????//error?出錯??
  • ????CON_STATE_CLOSE?????????????//close?連接關閉??
  • }?connection_state_t;??
  • 下面就是lighttpd的狀態機:

    在每個連接中都會保存這樣一個狀態機,用以表示當前連接的狀態。

    在連接建立以后,在connections.c/connection_accpet()函數中,lighttpd調用connection_set_state()函數,將新建立的連接的狀態設置為CON_STATE_REQUEST_START。在這個狀態中,lighttpd記錄連接建立的時間等信息。

    整個狀態機的核心函數是connections.c/ connection_state_machine()函數。

    函數的主體部分刪減之后如下:

    [cpp] view plain copy
  • int?connection_state_machine(server?*?srv,?connection?*?con)??
  • {??
  • ????int?done?=?0,?r;??
  • ????while?(done?==?0)??
  • ????{??
  • ????????size_t?ostate?=?con?->?state;??
  • ????????int?b;??
  • ????????//根據當前狀態機的狀態進行相應的處理和狀態轉換。??
  • ????????switch?(con->state)??
  • ????????{??
  • ????????case?CON_STATE_REQUEST_START:????/*?transient?*/??
  • ????????//do?something??
  • ????????case?CON_STATE_REQUEST_END:????/*?transient?*/??
  • ????????//do?something??
  • ????????case?CON_STATE_HANDLE_REQUEST:??
  • ????????//do?something??
  • ????????case?CON_STATE_RESPONSE_START:??
  • ????????//do?something??
  • ????????case?CON_STATE_RESPONSE_END:????/*?transient?*/??
  • ????????//do?something??
  • ????????case?CON_STATE_CONNECT:??
  • ????????//do?something??
  • ????????case?CON_STATE_CLOSE:??
  • ????????//do?something??
  • ????????case?CON_STATE_READ_POST:??
  • ????????//do?something??
  • ????????case?CON_STATE_READ:??
  • ????????//do?something??
  • ????????case?CON_STATE_WRITE:??
  • ????????//do?something??
  • ????????case?CON_STATE_ERROR:????/*?transient?*/??
  • ????????//do?something??
  • ????????default:??
  • ????????//do?something??
  • ????????????break;??
  • ????????}//end?of?switch(con?->?state)?...??
  • ????????if?(done?==?-1)??
  • ????????{??
  • ????????????done?=?0;??
  • ????????}??
  • ????????else?if?(ostate?==?con->state)??
  • ????????{??
  • ????????????done?=?1;??
  • ????????}??
  • ????}??
  • ????/*?something?else?*/??
  • ??
  • ????/*?將fd加入到fdevent系統中,等待IO事件。?
  • ?????*?當有數據可讀的時候,在main函數中,lighttpd調用這個fd對應的handle函數,?
  • ?????*?這里就是connection_handle_fdevent()函數。?
  • ?????*?這個函數一開始將連接加入到了joblist(作業隊列)中。?
  • ?????*/??
  • ????switch?(con->state)??
  • ????{??
  • ????case?CON_STATE_READ_POST:??
  • ????case?CON_STATE_READ:??
  • ????case?CON_STATE_CLOSE:??
  • ????????fdevent_event_add(srv->ev,?&(con->fde_ndx),?con->fd,?FDEVENT_IN);??
  • ????????break;??
  • ????case?CON_STATE_WRITE:??
  • ????????/*?request?write-fdevent?only?if?we?really?need?it?
  • ?????????*?-?if?we?have?data?to?write?
  • ?????????*?-?if?the?socket?is?not?writable?yet?
  • ?????????*/??
  • ????????if?(!chunkqueue_is_empty(con->write_queue)?&&??
  • ????????????(con->is_writable?==?0)&&?(con->traffic_limit_reached?==?0))??
  • ????????{??
  • ????????????fdevent_event_add(srv->ev,?&(con->fde_ndx),?con->fd,?FDEVENT_OUT);??
  • ????????}??
  • ????????else??
  • ????????{??
  • ????????????fdevent_event_del(srv->ev,?&(con->fde_ndx),?con->fd);??
  • ????????}??
  • ????????break;??
  • ????default:??
  • ????????fdevent_event_del(srv->ev,?&(con->fde_ndx),?con->fd);??
  • ????????break;??
  • ????}??
  • ????return?0;??
  • }??

  • 這個函數首先根據當前的狀態進入對應的switch分支執行相應的動作,然后根據情況進入下一個狀態。

    跳出switch語句之后,如果連接的狀態沒有改變,說明連接讀寫數據還沒有結束,但是需要等待IO事件,這時跳出循環,等待IO事件。

    如果在處理的過程中不需要等待IO事件,那么在while循環中,連接將被處理完畢并關閉。

    在我們的main函數中,之前討論過,在一個while循環中,處理超時,處理IO時間,之后有下面這段代碼:

    [cpp] view plain copy
  • for?(ndx?=?0;?ndx?<?srv->joblist->used;?ndx++)?{??
  • ??????connection?*con?=?srv->joblist->ptr[ndx];??
  • ??????handler_t?r;??
  • ??
  • ??????connection_state_machine(srv,?con);??
  • ??
  • ??????switch(r?=?plugins_call_handle_joblist(srv,?con))?{??
  • ??????case?HANDLER_FINISHED:??
  • ??????case?HANDLER_GO_ON:??
  • ??????????break;??
  • ??????default:??
  • ??????????log_error_write(srv,?__FILE__,?__LINE__,?"d",?r);??
  • ??????????break;??
  • ??????}??
  • ??
  • ??????con->in_joblist?=?0;??
  • ??}??

  • 這段代碼對joblist中的所有連接依次調用connection_state_machine()函數進行處理。

    下面說明下各狀態的主要內容:

    [cpp] view plain copy
  • CON_STATE_CONNECT??
  • 清除待讀取隊列中的數據-chunkqueue_reset(con->read_queue);??
  • 置con->request_count?=?0。(本次連接還未處理過請求)??
  • CON_STATE_REQUEST_START??/*transient?*/??
  • 記錄事件起始時間;??
  • con->request_count++(一次長連接最多可以處理的請求數量是有限制的);??
  • 轉移到CON_STATE_READ狀態。??
  • ??
  • CON_STATE_READ和CON_STATE_READ_POST??
  • connection_handle_read_state(srv,con);??
  • CON_STATE_REQUEST_END????/*transient?*/??
  • http_request_parse(srv,?con);??
  • 解析請求,若是POST請求則轉移到CON_STATE_READ_POST狀態,??
  • 否則轉移到CON_STATE_HANDLE_REQUEST狀態。??
  • CON_STATE_HANDLE_REQUEST??
  • http_response_prepare(srv,?con);??
  • 函數中調用??
  • handle_uri_raw;??
  • handle_uri_clean;??
  • handle_docroot;??
  • handle_physical;??
  • handle_subrequest_start;??
  • handle_subrequest。??
  • 如果函數返回了HANDLER_FINISHED,且con->mode!=DIRECT(事件已經被我們的業務插件接管),??
  • 則直接進入CON_STATE_RESPONSE_START。??
  • 否則lighttpd會做一些處理后再進入CON_STATE_RESPONSE_START狀態。??
  • 如果函數返回了HANDLER_WAIT_FOR_FD或??
  • HANDLER_WAIT_FOR_EVENT,??
  • 狀態依舊會停留在CON_STATE_HANDLE_REQUEST,等待事件或數據。??
  • 如果函數返回了HANDLER_ERROR,進入到CON_STATE_ERROR狀態。??
  • CON_STATE_RESPONSE_START??
  • connection_handle_write_prepare(srv,con);??
  • CON_STATE_WRITE??
  • connection_handle_write(srv,con);??
  • CON_STATE_RESPONSE_END??
  • 調用插件的handle_request_done接口。??
  • 如果是長連接,重新回到CON_STATE_REQUEST_START;否則調用插件的handle_connection_close接口。??
  • 執行connection_close(srv,?con);和connection_reset(srv,?con);將連接關閉。??
  • CON_STATE_ERROR???/*?transient?*/??
  • 調用插件handle_request_done;??
  • 調用插件handle_connection_close;??
  • 執行connection_close將連接關閉。??
  • CON_STATE_CLOSE??
  • connection_close(srv,?con);將連接關閉。??

  • 以上是狀態機的概況。

    總覽了狀態機,我們知道狀態機會針對相應的階段對事件進行處理,那么狀態機是如何處理這些事件的?

    事實上,對于事件的處理,一部分是由lighttpd完成的,而一部分是由插件完成的。插件中那些負責事件處理的接口分布在某幾個狀態中。我們只需在插件的各個階段完成指定工作并返回相應的返回值,就可以促使狀態機完成狀態切換,完成事件的整套處理流程,并最終由lighttpd完成事件的響應。

    在插件中,我們可以編寫代碼來注冊lighttpd提供的回調接口,lighttpd在初始化階段、狀態機執行階段、退出階段會分別調用這些回調函數,完成插件的實例化,初始化,連接重置,事件處理,插件釋放等功能。

    要了解lighttpd對插件的調用方式,需要明白一個概念:事件接管。

    對于每個事件,都有一個mode字段(con->mode)。該字段的定義:

    typedef enum { DIRECT, EXTERNAL } connection_type;

    連接對象有一個字段mode用來標識該連接是最初由服務器accept產生的客戶端連接還是插件產生的其他輔助連接,當mode=DIRECT時表示對應連接由lighttpd服務器accept產生,mode!=DIRECT時表示對應連接是由插件產生的。

    事件(con)初始化時mode是DIRECT;connection_reset(srv,con);

    lighttpd在大部分流程中會在入口檢查到mode != DIRECT時直接返回GO_ON。即:此事件由用戶插件接管,lighttpd不參與。

    用戶編寫的插件應通過將mode置為插件自身的ID達到接管的作用。插件ID是在插件加載時由插件的加載順序確定的,是插件的唯一標識。

    用戶編寫插件在每個接口的一開始應該判斷mode是否等于自身的ID,若相等才能繼續執行,否則直接退出,返回GO_ON。

    了解了以上概念之后,我們就可以理解lighttpd對插件的調用方式了:

    在lighttpd需要調用插件某一個階段的接口函數時,會對所有插件注冊在該處的接口順序調用,順序與插件加載順序相同。例如:調用uri_raw接口,會先調用A插件的mod_A_uri_raw,然后調用B插件的mod_B_uri_raw,直到將所有已加載插件這個位置的接口全部調用完成。但實際處理這次事件通常只有一個插件,即插件ID與mode相同的那個插件。

    因此,假設在CON_STATE_HANDLE_REQUEST狀態,lighttpd調用了插件的handle_uri_raw接口,但是我們有多個插件,每個插件都注冊了handle_uri_raw這個接口,lighttpd也能辨別出要使用哪個插件。

    如果插件在處理事件的過程中,想讓lighttpd接管,還需要把mode置為DIRECT才行。

    以上是lighttpd狀態機和插件的總覽概況。

    總結

    以上是生活随笔為你收集整理的Lighttpd源码分析之状态机与插件的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 69热在线观看| 小情侣高清国产在线播放 | 亚洲av乱码久久精品蜜桃 | 久久高清免费 | 毛片大片 | 欧美爱爱小视频 | 日本熟妇人妻中出 | 中日韩在线观看视频 | 一级黄色免费大片 | 性色av浪潮 | 性欧美大战久久久久久久 | 色姑娘av| 久久久久久久久久久久国产精品 | 黄色欧美视频 | 日本精品视频一区二区 | 国精产品一区二区 | 精品国产精品国产偷麻豆 | 性猛╳xxx乱大交 | 91资源在线观看 | 91在线欧美 | 国产成人精品一区二三区四区五区 | 中文字幕第18页 | 欧美日本精品 | 久久久夜色 | 不卡av一区二区 | 操大爷影院 | 日韩性xxx| 老司机av福利 | 午夜影视在线观看 | 性一交一乱一色一视频麻豆 | 亚洲一区二区国产精品 | 日本女人一级片 | 伊人狼人影院 | 中文字幕日韩无 | 国产成人精品av | 成人国产精品视频 | 久久精品2019中文字幕 | 色综合天天射 | 欧美精品hd | 久久久情 | 国产精品jizz在线观看无码 | 亚洲av成人一区二区国产精品 | 动漫一区二区三区 | 国产成人精品视频在线 | 天堂网av在线 | 中国新婚夫妻性猛交 | 日韩三级一区二区三区 | 成人国产精品久久 | 国产精品久久国产精麻豆96堂 | 色欧美88888久久久久久影院 | 特黄特色免费视频 | caoprom97| 吖v在线| 精品人妻一区二区乱码 | 美景之屋电影免费高清完整韩剧 | 制服丝袜在线视频 | 日韩av在线中文字幕 | 在线观看黄色大片 | 国产肉丝在线 | 国产尤物av尤物在线看 | 海角国产乱辈乱精品视频 | 亚洲欧美日韩精品在线观看 | 美女三级网站 | 成人黄色国产 | 久久精品国产免费 | 叶爱在线 | 青娱乐超碰在线 | 91久久精品一区二区 | 热久久精品免费视频 | 丰满人妻一区二区三区无码av | 超碰91人人 | 免费日韩一区二区 | 毛片网站视频 | 在线看的免费网站 | 一本色道久久综合狠狠躁的推荐 | 在线视频亚洲 | 少妇激情偷人爽爽91嫩草 | 精品久久久久久无码中文野结衣 | 日韩欧美亚洲国产 | 双性懵懂美人被强制调教 | 亚洲欧洲免费视频 | 91素人约啪 | 日日夜夜骑| 美女被艹视频网站 | 中文字幕免费高清在线观看 | 欧美老女人视频 | 成年人看的黄色片 | 亚洲一二三区在线 | 永久免费54看片 | 黑人一区二区三区 | 国产特黄级aaaaa片免 | 免费看黄色漫画 | 超碰97国产精品人人cao | 日日摸天天添天天添破 | 六月综合激情 | 国产午夜精品一区二区三区四区 | 二区视频在线观看 | 日本japanese乳偷乱熟 | 日日夜夜艹 |