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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【slighttpd】基于lighttpd架构的Server项目实战(8)—状态机机制回顾

發(fā)布時間:2024/1/23 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【slighttpd】基于lighttpd架构的Server项目实战(8)—状态机机制回顾 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50640270

有限狀態(tài)機FSM(Finite State Machine)

關于狀態(tài)機的一個極度確切的描述是它是一個有向圖形,由一組節(jié)點和一組相應的轉移函數組成。狀態(tài)機通過響應一系列事件而“運行”。每個事件都在屬于“當前” 節(jié)點的轉移函數的控制范圍內,其中函數的范圍是節(jié)點的一個子集。函數返回“下一個”(也許是同一個)節(jié)點。這些節(jié)點中至少有一個必須是終態(tài)。當到達終態(tài), 狀態(tài)機停止。
傳統應用程序的控制流程基本是順序的:遵循事先設定的邏輯,從頭到尾地執(zhí)行。很少有事件能改變標準執(zhí)行流程;而且這些事件主要涉及異常情況。“命令行實用程序”是這種傳統應用程序的典型例子。

另一類應用程序由外部發(fā)生的事件來驅動——換言之,事件在應用程序之外生成,無法由應用程序或程序員來控制。具體需要執(zhí)行的代碼取決于接收到的事件,或者它相對于其他事件的抵達時間。所以,控制流程既不能是順序的,也不能是事先設定好的,因為它要依賴于外部事件。

顯然,必須采取不同的技術來處理這些情況。它能處理任何順序的事件,并能提供有意義的響應——即使這些事件發(fā)生的順序和預計的不同。有限狀態(tài)機正是為了滿足這方面的要求而設計的。

lighttpd的狀態(tài)機機制簡要回顧

狀態(tài)機可以說是lighttpd最核心的部分。lighttpd將一個連接在不同的時刻分成不同的狀態(tài),狀態(tài)機則根據連接當前的狀態(tài),決定要對連接進行的處理以及下一步要進入的狀態(tài)。下面這幅圖描述了lighttpd的狀態(tài)機:

狀態(tài)機機制體現了清晰的邏輯,并且其設計可以讓我們更好地將服務器主體與插件結合起來,共同來完成請求的處理與響應。

下面我們將對lighttpd的狀態(tài)機進行簡要的回顧,具體的討論,可以參見以下博文:

Lighttpd1.4.20源碼分析 筆記 狀態(tài)機與插件

Lighttpd1.4.20源碼分析 筆記 狀態(tài)機之請求處理

Lighttpd1.4.20源碼分析 筆記 狀態(tài)機之response

Lighttpd1.4.20源碼分析 筆記 狀態(tài)機之錯誤處理和連接關閉

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

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

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

狀態(tài)定義如下:

typedef enum {CON_STATE_CONNECT, //connect 連接開始CON_STATE_REQUEST_START, //restart開始讀取請求CON_STATE_READ, //read讀取并解析請求CON_STATE_REQUEST_END, //reqend讀取請求結束CON_STATE_READ_POS, //readpost讀取post數據CON_STATE_HANDLE_REQUEST, //handlereq處理請求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;

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

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

int connection_state_machine(server * srv, connection * con) {int done = 0, r;while (done == 0){size_t ostate = con -> state;int b;//根據當前狀態(tài)機的狀態(tài)進行相應的處理和狀態(tài)轉換。switch (con->state){case CON_STATE_REQUEST_START: /* transient *///do somethingcase CON_STATE_REQUEST_END: /* transient *///do somethingcase CON_STATE_HANDLE_REQUEST://do somethingcase CON_STATE_RESPONSE_START://do somethingcase CON_STATE_RESPONSE_END: /* transient *///do somethingcase CON_STATE_CONNECT://do somethingcase CON_STATE_CLOSE://do somethingcase CON_STATE_READ_POST://do somethingcase CON_STATE_READ://do somethingcase CON_STATE_WRITE://do somethingcase CON_STATE_ERROR: /* transient *///do somethingdefault://do somethingbreak;}//end of switch(con -> state) ...if (done == -1){done = 0;}else if (ostate == con->state){done = 1;}}/* something else */return 0; }

可以看到,事實上,狀態(tài)機的主體就是一個switch語句,它根據不同的state進入相應的分支,進行事件的處理,在一個狀態(tài)處理結束時,會通過調用connection_set_state()函數來設置新的狀態(tài),從而推動狀態(tài)機的運轉。

在lighttpd中,各個狀態(tài)所做的工作總結如下:

【CON_STATE_CONNECT】清除待讀取隊列中的數據-chunkqueue_reset(con->read_queue); 置con->request_count = 0。【CON_STATE_REQUEST_START】 /*transient */過渡狀態(tài); 記錄事件起始時間; con->request_count++(一次長連接最多可以處理的請求數量是有限制的); 轉移到CON_STATE_READ狀態(tài)。【CON_STATE_READ】和【CON_STATE_READ_POST】調用connection_handle_read_state(srv,con); 服務器從連接讀取HTTP頭并存放在con->requeset.request中。 兩者的區(qū)別:POST的數據量比較大,可能需要臨時文件來存儲。【CON_STATE_REQUEST_END】 /*transient */調用http_request_parse(srv, con)解析請求; 函數首先解析Request line,解析出來的結果存放在 con->request.http_method, con->request.http_version和 con->request.uri中; 解析完request line后,開始分析header lines。 將field name和value保存到con->request.headers中。 解析完后判斷是否有POST數據,有則進入CON_STATE_READ_POST狀態(tài), 否則轉移到CON_STATE_HANDLE_REQUEST狀態(tài)。【CON_STATE_HANDLE_REQUEST】本狀態(tài)需要決定如何處理請求; 該狀態(tài)調用http_response_prepare函數,根據返回值進行相應的處理。 如果函數返回HANDLER_FINISHED,且con->mode!=DIRECT(事件已被插件接管), 則直接進入CON_STATE_RESPONSE_START。 否則lighttpd會做一些處理后再進入CON_STATE_RESPONSE_START狀態(tài)。 如果函數返回了HANDLER_WAIT_FOR_FD或 HANDLER_WAIT_FOR_EVENT, 狀態(tài)依舊會停留在CON_STATE_HANDLE_REQUEST,等待事件或數據。 如果函數返回了HANDLER_ERROR,進入到CON_STATE_ERROR狀態(tài)。【CON_STATE_RESPONSE_START】調用connection_handle_write_prepare(srv,con); 根據客戶端請求的method來設置response的headers; 狀態(tài)機進入CON_STATE_WRITE狀態(tài)。【CON_STATE_WRITE】調用connection_handle_write(srv,con); 將響應寫回給客戶端,注意,數據可能一次發(fā)送不完。 如果數據發(fā)送完畢,狀態(tài)機進入CON_STATE_RESPONSE_END狀態(tài)。【CON_STATE_RESPONSE_END】通知所有插件連接處理完畢; 如果是長連接,重新回到CON_STATE_REQUEST_START; 否則通知所有插件連接關閉; 執(zhí)行connection_close(srv, con); 和connection_reset(srv, con); 連接關閉。【CON_STATE_ERROR】 /* transient */調用插件handle_request_done; 調用插件handle_connection_close; 執(zhí)行connection_close將連接關閉。【CON_STATE_CLOSE】調用connection_close(srv, con); 將連接關閉, 注意,這里服務器主動關閉連接,使用shutdown而不是close。

好了,回顧完lighttpd的狀態(tài)機機制之后,下一節(jié)中,我們將把狀態(tài)機機制引入到我們的項目當中!~

總結

以上是生活随笔為你收集整理的【slighttpd】基于lighttpd架构的Server项目实战(8)—状态机机制回顾的全部內容,希望文章能夠幫你解決所遇到的問題。

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