引言
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的上下文,也稱爲一個實例句柄。它的成員如下:
struct mg_context { int stop_flag; /* Should we stop event loop */ SSL_CTX *ssl_ctx; /* SSL context */ FILE *access_log; /* Opened access log */ FILE *error_log; /* Opened error log */ struct socket listeners[MAX_LISTENING_SOCKETS]; int num_listeners; struct callback callbacks[MAX_CALLBACKS]; int num_callbacks; char *options[NUM_OPTIONS]; /* Configured opions */ pthread_mutex_t opt_mutex[NUM_OPTIONS]; /* Option protector */ int max_threads; /* Maximum number of threads */ int num_threads; /* Number of threads */ int num_idle; /* Number of idle threads */ pthread_mutex_t thr_mutex; /* Protects (max|num)_threads */ pthread_cond_t thr_cond; pthread_mutex_t bind_mutex; /* Protects bind operations */ struct socket queue[20]; /* Accepted sockets */ int sq_head; /* Head of the socket queue */ int sq_tail; /* Tail of the socket queue */ pthread_cond_t empty_cond; /* Socket queue empty condvar */ pthread_cond_t full_cond; /* Socket queue full condvar */ mg_spcb_t ssl_password_callback; mg_callback_t log_callback; };
這個結構體在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處理函數。他們原型是:
/* * Register SSL password handler. * This is needed only if SSL certificate asks for a password. Instead of * prompting for a password on a console a specified function will be called. */ typedef int (*mg_spcb_t)(char *buf, int num, int w, void *key); /* * User-defined callback function prototype for URI handling, error handling, * or logging server messages. */ typedef void (*mg_callback_t)(struct mg_connection *, const struct mg_request_info *info, void *user_data);
是上面講了那麼多感覺挺亂的,下面用張圖片來形象表示一下:
圖1、mg_context結構體的成員
2、mg_connection詳解
故名思意,這個結構體用戶保存client的連接信息。它的成員如下:
/* * Client connection. */ struct mg_connection { struct mg_request_info request_info; struct mg_context *ctx; /* Mongoose context we belong to*/ SSL *ssl; /* SSL descriptor */ struct socket client; /* Connected client */ time_t birth_time; /* Time connection was accepted */ bool_t free_post_data; /* post_data was malloc-ed */ bool_t embedded_auth; /* Used for authorization */ uint64_t num_bytes_sent; /* Total bytes sent to client */ };
上面的字段意思都很明顯這裏就不一一闡述了。可以看出, 每個連接都保存了一個Mongoose上下文(mg_context * ctx),這個很重要,對連接請求進行處理時都會用到。這裏也可以看出mg_context相當於一個實例句柄。
結構體mg_request_info用於保存每個請求的信息,例如,當我打開博客主頁http://www.cnblogs.com/skynet/的時候,會發出一個請求信息,包括請求的方法是POST還是GET等、uri即http://www.cnblogs.com/skynet/、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結構定義如下:
/* * This structure contains full information about the HTTP request. * It is passed to the user-specified callback function as a parameter. */ struct mg_request_info { char *request_method; /* "GET", "POST", etc */ char *uri; /* Normalized URI */ char *query_string; /* \0 - terminated */ char *post_data; /* POST data buffer */ char *remote_user; /* Authenticated user */ long remote_ip; /* Client's IP address */ int remote_port; /* Client's port */ int post_data_len; /* POST buffer length */ int http_version_major; int http_version_minor; int status_code; /* HTTP status code */ int num_headers; /* Number of headers */ struct mg_header { char *name; /* HTTP header name */ char *value; /* HTTP header value */ } http_headers[64]; /* Maximum 64 headers */ };
從字段都能夠故名思意,這裏就不再闡述了。
4、其他數據結構
除了上面3個主要的數據結構,還有其它一些數據也默默地貢獻着自己的一份力量。作爲一個整體,少了它們Mongoose也只能淪爲廢物。下面我就列舉幾個:
/* * Structure used by mg_stat() function. Uses 64 bit file length. */ struct mgstat { bool_t is_directory; /* Directory marker */ uint64_t size; /* File size */ time_t mtime; /* Modification time */ }; struct mg_option { const char *name; const char *description; const char *default_value; int index; bool_t (*setter)(struct mg_context *, const char *); }; /* * Structure used to describe listening socket, or socket which was * accept()-ed by the master thread and queued for future handling * by the worker thread. */ struct socket { SOCKET sock; /* Listening socket */ struct usa lsa; /* Local socket address */ struct usa rsa; /* Remote socket address */ bool_t is_ssl; /* Is socket SSL-ed */ }; /* * Unified socket address. For IPv6 support, add IPv6 address structure * in the union u. */ struct usa { socklen_t len; union { struct sockaddr sa; struct sockaddr_in sin; } u; }; /* * Specifies a string (chunk of memory). * Used to traverse comma separated lists of options. */ struct vec { const char *ptr; size_t len; }; /* * Dynamically loaded SSL functionality */ struct ssl_func { const char *name; /* SSL function name */ void (*ptr)(void); /* Function pointer */ };
5、總結
至此,我們介紹了Mongoose中使用的一些數據結構,搞清楚這些數據結構對整個項目的理解非常重要。它們遍佈在項目的每個角落(雖然項目比較小)。
出處:http://www.cnblogs.com/skynet/
本文基於署名 2.5 中國大陸許可協議發佈,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名吳秦(包含鏈接)