本篇文章主要記錄說明使用nginx時,開闢一個簡單http模塊的時序圖,還有nginx中封裝的數據結構及其處理函數。
1.如何開發一個充滿異步調用,無阻塞的http模塊?
首先,我們需要把程序嵌如到nginx中(最終變異處的二進制程序nginx要包含我們的代碼)。
然後,這個http模塊要能介入到處理流程中。
在正式請求處理時,還要可以獲取nginx框架定義的數據結構,解析後的用戶請求信息
業務執行完畢後,則要考慮發送響應給用戶(包括將磁盤中的文件以http包體的形式發送給用戶)
我們都是討論C/C++語言來進行編寫,雖然nginx官方不倡導,本文章不討論各個核心模塊如何配合工作。
2.關於http模塊的調用。
1.首先nginx是master和多個worker進程的組合,worket進程會在一個for循環語句例反覆調用時間模塊檢測網絡事件,即檢測到TCP請求(接收到SYN包),將會爲它建立TCP連接。
2.成功建立連接後根據nginx.conf文件中的配置會交由http框架處理。
ps:http框架會試圖接收完整的HTTP頭部,並在接收到完整的http頭部後將請求的uri和nginx.conf裏的location配置項的匹配來決定如何分發。
3.處理結束後會調用過濾模塊,然後根據配置文件決定自己的行爲。
時序圖:
ps:需要注意HTTP框架到具體http模塊間數據流的傳遞,還有之間的協同,以後會寫到。
模塊命名爲:ngx_http_mytest_module.c
下面進入正題,所以下nginx中封裝的數據類型還有數據結構
以下都爲linux操作系統下的解釋:
1.×××的封裝:
typedef intptr_t ngx_int_t; //代表int typedef uintptr_t ngx_uint_t; //代表unsinged int
2.數據結構:
1.字符串
//字符串的封裝。其中data不是普通的字符串,很有可能不以‘0’結尾。必須配合len typedef struct{ size_t len; u_char *data; }ngx_str_t; //用於字符串的比較函數,因爲未必有0,所以必須用ngx_strncmp比較 #define ngx_strncmp(s1,s2,n) strncmp((const char *)s1,(const char *)s2,n)
2.鏈表容器:
//這裏封裝的鏈表容器使用是很頻繁,比如http頭部就是使用這個數據結構來存儲的。 typedef struct ngx_list_part_s ngx_list_part_t; struct ngx_list_part_s { void *elts;//數組的起始地址 ngx_uint_t nelts; //已經存在多少個元素,必須小於nalloc ngx_list_part_t *next; //下一個地址 } typedef ngx_list_part_s { ngx_list_part_t *last; //鏈表最後一個元素 ngx_list_part_t part; //鏈表第一個數組元素 size_t size; //每一個數組元素佔用空間大小 ngx_uint_t nalloc; //數組可以存儲多少個數據 ngx_pool_t *poll; //nginx內存池的對象。 }ngx_list_t; //下面是封裝的ngx_list_t的函數借口 ngx_list_t *ngx_list_create(ngx_pool_t *pool,ngx_uint_t n,size_t size);//創建 //返回創建鏈表地址。 static ngx_inline ngx_int_t ngx_list_init(ngx_list_t,ngx_pool_t *pool,ngx_uint_t n,size_t size); //初始化 //返回NGX_OK, NGX_ERROR; void *ngx_list_push(ngx_list_t *list);//添加元素、 //遍歷鏈表 ngx_list_part_t *part = &testlist.part; ngx_str_t = part->elts; for(i = 0;;i++) { if(i >= part->nelts) { if(part->next = NULL) break; part = part->next; header = part->elts; i = 0 ; } printf("%*s\n",str[i].len,str[i].data); }
3.key/value (用於存儲http頭部信息)
typedef struct { ngx_uint_t hash; ngx_str_t key; ngx_str_t value; u_char* lowcase_key; //全是小寫的key字符串。 }ngax_table_elt_t;
4.緩衝區的數據結構
typedef struct ngx_buf_s ngx_buf_t; typedef void * ngx_buf_tag_t; struct ngx_buf_s{ u_char *pos; //數據處理的開始位置; u_char *last; //數據處理的結束位置; off_t file_pos; //處理文件的文件開始位置 off_t file_last; //處理文件的文件結束位置 u_char *start; //如果ngx_buf_t用於內存,那麼指向這個內存的起始地址 u_char *end; //緩衝區內存的末尾 ngx_buf_tag_t tag; //緩衝區類型 ngx_file_t *file; //引用的文件 ngx_buf_t *shadow; //影子緩衝區,很少用,設計複雜,簡單理解爲多個指向同一塊內存 unsigned temporary:1; //臨時內存標誌位,1表示這段內存可以修改 unsigned memory:1; //標誌位,爲1表示數據在內存中且內存不可以修改 unsigned mmap:1; //1表示這頓啊內存用mmap系統調用映射過來的,不可以被修改 unsigned recycled:1; //1表示可以回收 unsigned in_file:1; //1表示這段緩衝區處理的是文件而不是內存 unsigned flush:1; //1表示需要執行flush操作 unsigned sync:1; //是否需要使用同步方式 unsigned last_buf:1; //表示是否爲最後一塊緩衝區 unsigned last_in_chain:1; //表示是否是ngx_chain_t中的最後一塊緩衝區 unsigned last_shadow:1; //是否是最後一個影子緩衝區,與shadow域配合使用。不建議使用 unsigned temp_file:1; //表示當前緩衝去是否是臨時文件 }
5.ngx_chain_t(與ngx_buf_t配合使用,存儲向用戶發送的HTTP包體,結尾設置爲null)
typedef struct ngx_chain_s ngx_chain_t; struct ngx_chain_s{ ngx_buf_t *buf; ngx_chain_t *next; }
以上就是nginx的數據結構。