天天看點

Mongoose源碼剖析:核心處理子產品

前面我們介紹了

mongoose所有的幾個主要的資料結構mg_context、mg_connection、mg_request_info,還有mongoose的

生命主線。有了這些基礎就可以來看看mongoose的核心處理工作是怎樣的。如果你還沒有閱讀前面的文章,你可以通過下面的隧道直通:

<a href="http://www.cnblogs.com/skynet/archive/2010/07/24/1784110.html" target="_blank">mongoose源碼剖析:外篇之web伺服器</a>

<a href="http://www.cnblogs.com/skynet/archive/2010/07/24/1784322.html" target="_blank">mongoose源碼剖析:introduction and installation</a>

<a href="http://www.cnblogs.com/skynet/archive/2010/07/24/1784454.html">mongoose源碼剖析:資料結構篇</a>

<a href="http://www.cnblogs.com/skynet/archive/2010/07/24/1784476.html">mongoose源碼剖析:mongoose的工作模型</a>

本文從下面幾個方面去介紹mongoose的核心處理子產品,連接配接建立之後的:

請求解析

請求驗證

請求滿足

mongoose的主線程master_thread在接受一個新的client連接配接請求時,會将client的socket位址放入一個queue(調用put_socket()方法);而當worker_thread線程處理client的請求時,是通過get_socket()方法從queue取出client的socket位址,然後與它建立連接配接。

立連接配接就用到了資料結構mg_connection,該結構儲存了client的連接配接資訊。該結構體中有兩個非常重要的成

員:mg_request_info用于儲存client的請求資訊、mg_context用于儲存該client請求的mongoose上下文。建立連

接的代碼片段如下:

其中以ssl_開頭的函數都是加載自ssl的庫,加載庫調用了如下接口:static bool_t set_ssl_option(struct mg_context *ctx, const char *pem),有興趣的話你可以追蹤下去。

建立連接配接之後,在process_new_connection中會去讀取client的請求資訊,然後才去解析請求。讀取client端的請求的資訊用到了下面的方法:

其中pull()方法的代碼如下:

這樣client發送的http請求消息就被worker_thread讀取到了,并存儲在buf中, 接下來的工作就是解析讀取到的請求資訊,明白client到底想幹嘛,說白了就從buf中提取資訊并存儲到結構體mg_request_info中去。

請求解析的工作都封裝在parse_http_request()函數彙中,它的代碼如下:

它的主要工作就是從buf中提取出資訊放到ri(一個mg_request_info結構)中去,因為buf是一個無結構的字元串數組。要将它存儲到ri中去,需要找到對應的子串。

這裡主要用到了skip()、parse_http_headers()方法,其中skip()很關鍵,代碼如下:

我們來分析一下skip的作用及實作。如要從buf中解析出client請求的methods是哪個(put、get、post等等)?隻需要這樣做就可以了:

ri-&gt;request_method = skip(&amp;buf, " ");

為了分析,到底是如何實作這個的,我在porcess_new_connection()中加入下面一行輸出buf資訊的代碼:

Mongoose源碼剖析:核心處理子產品
Mongoose源碼剖析:核心處理子產品

看到第一行就是get /favicon.ico http/1.1。知道了buf中的字元資訊,但在我們分析skip(&amp;buf, " ")是如何提取出get的之前,還要知道strcspn、strspn的作用,下面是它們的原型:

下面解釋它們的作用:

description        the strspn() function calculates the length of the initial segment of s which consists entirely of characters in accept.        the strcspn() function calculates the length of the initial segment  of s which consists entirely of characters not in reject. return value        the  strspn()  function returns the number of characters in the initial segment of s which consist only of characters from accept.        the strcspn() function returns the number of characters in the  initial segment of s which are not in the string reject.

現在已經萬事俱備了,skip(&amp;buf, " ")的執行情況如下:

Mongoose源碼剖析:核心處理子產品

其餘的解析工作也是類似地進行的,我就不一一闡述了。

請求驗證分布在從連接配接請求開始到請求得到回應的整個過程中。在請求解析之前,比如驗證socket的合法性等。在請求解析之後,從buf中解析出

http請求消息的各個字段之後,就做一些簡單的驗證工作,比如說http版本的驗證。如果在解析buf時出錯,說明請求的格式不對。

而且在滿足client請求的時候也要進行一些驗證,諸如是否有浏覽目錄的權限、請求的檔案是否存在等等,我就不在詳述了。

在parse_http_request()之後,調用analyze_request()去滿足client的請求。這是mongoose的核心

内容,也是不同web伺服器軟體相差別的地方。analyze_request()封裝了一些操作,即調用了一些接口去滿足client的請求,代碼如

下:

上面的代碼比較好了解我就不把它嚼爛之後,再展現給你!那樣也沒有意思~\(≧▽≦)/~啦啦啦。感興趣的自己去逐一分析。