1. 程式人生 > >web伺服器之mongoose:資料結構

web伺服器之mongoose:資料結構

原文網址:https://blog.csdn.net/yangxuan12580/article/details/51659762

 

Mongoose中有幾個資料結構扮演著重要的角色,它們分別是:

struct mg_context:儲存Mongoose的上下文,幾乎每個函式都有mg_context引數

struct mg_connection:儲存HTPP連線資訊

struct mg_request_info:儲存HTTP請求的資訊,這個結構體傳遞給URL處理函式

 

我之所以現在這裡介紹它,因為之後的分析工作中要用到它們,如果在讀完本文後還不能很好的理解,請將問題帶到後續文章中或程式碼分析中去,你會找到答案的。下面分別介紹它們。

本文的主要內容如下:

1、mg_context詳解

2、mg_connection詳解

3、mg_request_info詳解

4、其他資料結構

5、總結

 

1、mg_context詳解

 

mg_context結構體——表示Mongoose的上下文,也稱為一個例項控制代碼。它的成員如下:

  1. struct mg_context {
  2.     int        stop_flag;    /* Should we stop event loop    */
  3.     SSL_CTX        *ssl_ctx;    /* SSL context            */
  4.  
  5.     FILE        *access_log;    /* Opened access log        */
  6.     FILE        *error_log;    /* Opened error log        */
  7.  
  8.     struct socket    listeners[MAX_LISTENING_SOCKETS];
  9.     int        num_listeners;
  10.  
  11.     struct callback    callbacks[MAX_CALLBACKS];
  12.     int        num_callbacks;
  13.  
  14.     char        *options[NUM_OPTIONS];    /* Configured opions    */
  15.     pthread_mutex_t    opt_mutex[NUM_OPTIONS];    /* Option protector    */
  16.  
  17.     int        max_threads;    /* Maximum number of threads    */
  18.     int        num_threads;    /* Number of threads        */
  19.     int        num_idle;    /* Number of idle threads    */
  20.     pthread_mutex_t    thr_mutex;    /* Protects (max|num)_threads    */
  21.     pthread_cond_t    thr_cond;
  22.     pthread_mutex_t    bind_mutex;    /* Protects bind operations    */
  23.  
  24.     struct socket    queue[20];    /* Accepted sockets        */
  25.     int        sq_head;    /* Head of the socket queue    */
  26.     int        sq_tail;    /* Tail of the socket queue    */
  27.     pthread_cond_t    empty_cond;    /* Socket queue empty condvar    */
  28.     pthread_cond_t    full_cond;    /* Socket queue full condvar    */
  29.  
  30.     mg_spcb_t    ssl_password_callback;
  31.     mg_callback_t    log_callback;
  32. };

這個結構體在mg_start()中建立和初始化,其它函式大部分都會用它。因此mg_start()應該首先被呼叫。它非常重要,幾乎所有的函式都要用到它。

 

1)、stop_flag表示是否應該停止的標記,它有三個可能的值0、1、2。 stop_flag=0表示 不應該停止,這是初始值;stop_flag=1表示停止,在mg_stop()函式中的一開始設定stop_flag=1,這會觸發mg_fini(),且在mg_stop()中會一直等待mg_fini執行完成;stop_flag=2用於通知mg_stop(),mg_fini已經執行完成,stop_flag=2在mg_fini函式中的末尾設定。

 

2)、ssl_ctx是結構體ssl_ctx_st的例項,它來自OpenSSL開源專案,作者把它放到這裡的原因是使其獨立於OpenSSL的原始碼安裝,這樣只有系統上面安裝有SSL庫,mongoose+SSL就能編譯通過。

 

3)、access_log、error_log很明顯是指向訪問日誌檔案、錯誤日誌檔案。

 

4)、listeners陣列儲存mongoose建立的多個web server,每個web server都是listeners陣列中的一個元素。例如,一個伺服器可以分別在埠8080、8888建立web server,這樣8080埠的那個server是listerns陣列中的一個元素,8888埠的那個server也是listeners陣列中的一個元素。換句話說,listeners陣列表示web server的socket地址。num_listeners表示listeners陣列的元素個數。

 

5)、callbacks是結構體callback的陣列,而callback本身是一個結構體,包含幾個回撥控制代碼。num_callbacks是callbacks陣列元素的個數。

 

6)、options陣列,是用於儲存配置選項的,例如埠號、工作目錄等等。opt_mutext對配置進行操作的互斥變數。

 

7)、max_threads表示允許的最大執行緒數量、num_threads表示當前的執行緒數量、num_idle表示空閒的執行緒數量。之所以會有空閒程序,是因為當建立一個執行緒處理連線請求之後,它會保持一段時間空閒而不是直接銷燬。如果這裡再用新的連線到來或等待佇列中有需要處理的連線,空閒程序會被分配去處理。

 

8)、thr_mutex、thr_cond、bind_mutex是用於互斥訊號量和條件變數。

 

9)、queue[20]佇列陣列儲存client的連線請求,每個元素都是client的socket。sq_head、sq_tail分別是佇列頭、尾用於操作佇列queue。empty_cond、full_cond分別表示佇列是否為空、滿的條件變數。

 

10)、ssl_password_callback和log_callback都是函式指標,分別指向SSL密碼處理函式、log處理函式。他們原型是:

  1. /*
  2.  * Register SSL password handler.
  3.  * This is needed only if SSL certificate asks for a password. Instead of
  4.  * prompting for a password on a console a specified function will be called.
  5.  */
  6. typedef int (*mg_spcb_t)(char *buf, int num, int w, void *key);
  7.  
  8. /*
  9.  * User-defined callback function prototype for URI handling, error handling,
  10.  * or logging server messages.
  11.  */
  12. typedef void (*mg_callback_t)(struct mg_connection *,
  13.         const struct mg_request_info *info, void *user_data);

是上面講了那麼多感覺挺亂的,下面用張圖片來形象表示一下:

    

                                   圖1 mg_context結構體

2、mg_connection詳解

 

故名思意,這個結構體使用者儲存client的連線資訊。它的成員如下:

  1. /*
  2.  * Client connection.
  3.  */
  4. struct mg_connection {
  5.     struct mg_request_info    request_info;
  6.     struct mg_context *ctx;        /* Mongoose context we belong to*/
  7.     SSL        *ssl;        /* SSL descriptor        */
  8.     struct socket    client;        /* Connected client        */
  9.     time_t        birth_time;    /* Time connection was accepted    */
  10.     bool_t        free_post_data;    /* post_data was malloc-ed    */
  11.     bool_t        embedded_auth;    /* Used for authorization    */
  12.     uint64_t    num_bytes_sent;    /* Total bytes sent to client    */
  13. };

上面的欄位意思都很明顯這裡就不一一闡述了。可以看出, 每個連線都儲存了一個Mongoose上下文(mg_context * ctx),這個很重要,對連線請求進行處理時都會用到。這裡也可以看出mg_context相當於一個例項控制代碼。

 

結構體mg_request_info用於儲存每個請求的資訊,例如,當開啟http://www.google.com的時候,會發出一個請求資訊,包括請求的方法是POST還是GET等、uri即http://www.google.com、http版本、還有一些http頭資訊等等。關於結構體mg_request_info的詳細資訊參見下一小節。

mg_connection的影象表示如下:

                                 圖2  mg_connection結構體的成員

3、mg_request_info詳解

 

這個結構體儲存每次client傳送請求,即是一個HTTP請求報文資訊。而我們知道HTTP的請求報文資訊的格式如下:

    

 

                      圖3 HTTP請求的格式

 

根據這個資訊,可以更好地理解mg_request_info。mg_request_info結構定義如下:

  1. /*
  2.  * This structure contains full information about the HTTP request.
  3.  * It is passed to the user-specified callback function as a parameter.
  4.  */
  5. struct mg_request_info {
  6.     char    *request_method;    /* "GET", "POST", etc    */
  7.     char    *uri;            /* Normalized URI    */
  8.     char    *query_string;        /* \0 - terminated    */
  9.     char    *post_data;        /* POST data buffer    */
  10.     char    *remote_user;        /* Authenticated user    */
  11.     long    remote_ip;        /* Client's IP address    */
  12.     int    remote_port;        /* Client's port    */
  13.     int    post_data_len;        /* POST buffer length    */
  14.     int    http_version_major;
  15.     int    http_version_minor;
  16.     int    status_code;        /* HTTP status code    */
  17.     int    num_headers;        /* Number of headers    */
  18.     struct mg_header {
  19.         char    *name;        /* HTTP header name    */
  20.         char    *value;        /* HTTP header value    */
  21.     } http_headers[64];        /* Maximum 64 headers    */
  22. };

從欄位都能夠故名思意,這裡就不再闡述了。

 

4、其他資料結構 

 

除了上面3個主要的資料結構,還有其它一些資料也默默地貢獻著自己的一份力量。作為一個整體,少了它們Mongoose也只能淪為廢物。下面我就列舉幾個:

  1. /*
  2.  * Structure used by mg_stat() function. Uses 64 bit file length.
  3.  */
  4. struct mgstat {
  5.     bool_t        is_directory;    /* Directory marker        */
  6.     uint64_t    size;        /* File size            */
  7.     time_t        mtime;        /* Modification time        */
  8. };
  9.  
  10. struct mg_option {
  11.     const char    *name;
  12.     const char    *description;
  13.     const char    *default_value;
  14.     int        index;
  15.     bool_t (*setter)(struct mg_context *, const char *);
  16. };
  17. /*
  18.  * Structure used to describe listening socket, or socket which was
  19.  * accept()-ed by the master thread and queued for future handling
  20.  * by the worker thread.
  21.  */
  22. struct socket {
  23.     SOCKET        sock;        /* Listening socket        */
  24.     struct usa    lsa;        /* Local socket address        */
  25.     struct usa    rsa;        /* Remote socket address    */
  26.     bool_t        is_ssl;        /* Is socket SSL-ed        */
  27. };
  28. /*
  29.  * Unified socket address. For IPv6 support, add IPv6 address structure
  30.  * in the union u.
  31.  */
  32. struct usa {
  33.     socklen_t len;
  34.     union {
  35.         struct sockaddr    sa;
  36.         struct sockaddr_in sin;
  37.     } u;
  38. };
  39.  
  40. /*
  41.  * Specifies a string (chunk of memory).
  42.  * Used to traverse comma separated lists of options.
  43.  */
  44. struct vec {
  45.     const char    *ptr;
  46.     size_t        len;
  47. };
  48. /*
  49.  * Dynamically loaded SSL functionality
  50.  */
  51. struct ssl_func {
  52.     const char    *name;        /* SSL function name    */
  53.     void        (*ptr)(void);    /* Function pointer    */
  54. };

5、總結

 

至此,我們介紹了Mongoose中使用的一些資料結構,搞清楚這些資料結構對整個專案的理解非常重要。它們遍佈在專案的每個角落(雖然專案比較小)