前言
不能保證每天都有時(shí)間學(xué)這個(gè),畢竟其他方面還有很多的事情需要做感挥,但一定會(huì)利用好時(shí)間缩搅,充實(shí)自己。另外链快,大概掃了下Nginx自己封裝的數(shù)據(jù)結(jié)構(gòu)類型誉己,確實(shí)還是蠻多的。所以域蜗,暫時(shí)打算學(xué)一點(diǎn)巨双,更新一點(diǎn)。這一篇也主要是為自己開發(fā)一個(gè)簡單HTTP模塊做準(zhǔn)備霉祸。
封裝的數(shù)據(jù)結(jié)構(gòu)
Nginx為了做到跨平臺(tái)筑累,追求極致高效,自身定義丝蹭、封裝了一些數(shù)據(jù)結(jié)構(gòu)慢宗。就我個(gè)人來說,無論是對(duì)這一類統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)的封裝風(fēng)格奔穿,還是其中的封裝技巧(盡可能地少占用內(nèi)存)镜沽,都是非常喜歡,大贊一個(gè)贱田。
1)整型 <ngx_config.h>
typedef intptr_t? ? ? ? ngx_int_t;
typedef uintptr_t? ? ? ngx_uint_t;
C99 標(biāo)準(zhǔn)定義了 intptr_t 和 uintptr_t 類型是給一個(gè)可以持有一個(gè)指針值的整型變量缅茉。
2)字符串型 <ngx_string.h>
typedef struct {
? ? size_t? ? ? len;? // 指向字符串首字符地址
? ? u_char? ? *data; // 字符串長度
} ngx_str_t;
可以看出,這里基本沒有'\0'什么事了男摧。這種封裝的優(yōu)點(diǎn):1蔬墩,減少計(jì)算字符串長度次數(shù),可以直接用耗拓;2拇颅,可以重復(fù)引用一段字符串內(nèi)存,長度表示結(jié)束乔询。這樣樟插,不用對(duì)一段字符串再copy一份自己的副本,因?yàn)閐ata指針可以指向任何字符串地址竿刁,這樣可以減少不必要的內(nèi)存分配與拷貝岸夯。也因?yàn)檫@個(gè)特性,Nginx中必須謹(jǐn)慎對(duì)一段字符串做出修改们妥;另外猜扮,任何試圖將ngx_str_t的data成員當(dāng)作字符串來使用,都可能導(dǎo)致內(nèi)存越界监婶!
因?yàn)椴淮嬖凇甛0’旅赢,Nginx專門提供自己有關(guān)ngx_str_t的操作的API齿桃。簡單筆記:
// 以{...}括住,只適用于字符串賦值初始化煮盼,計(jì)算str長度為sizeof關(guān)鍵字短纵,因此str為字符串常量!? ? ?
#define ngx_string(str)? ? { sizeof(str) - 1, (u_char *) str }
#define ngx_null_string? ? { 0, NULL }
// 字符串賦值僵控,text為字符串常量香到!因?yàn)槭莾尚写a,在if/for/while等語句中單獨(dú)使用需要用花括號(hào)括起來报破!
#define ngx_str_set(str, text)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
? ? (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
#define ngx_str_null(str)? (str)->len = 0; (str)->data = NULL?
另外Nginx簡單封裝了glibc的字符串操作API悠就,具體見ngx_string.h。 ??
3)鏈表容器 <ngx_list.h>
/* 描述鏈表的一個(gè)結(jié)點(diǎn)充易,此節(jié)點(diǎn)實(shí)際上是一個(gè)數(shù)組梗脾,擁有一段連續(xù)內(nèi)存 */
typedef struct ngx_list_part_s? ngx_list_part_t;
struct ngx_list_part_s {
? ? void? ? ? ? ? ? *elts;? // 指向數(shù)組起始地址
? ? ngx_uint_t? ? ? ? nelts;? // 表示數(shù)組中已經(jīng)使用多少個(gè)元素,其值 <= ngx_list_t中的nalloc
? ? ngx_list_part_t? *next;? // 下一個(gè)鏈表節(jié)點(diǎn)
};
/* 描述整個(gè)鏈表 */
typedef struct {
? ? ngx_list_part_t? *last;? // 鏈表尾節(jié)點(diǎn)
? ? ngx_list_part_t? part;? // 鏈表首節(jié)點(diǎn)
? ? size_t? ? ? ? ? ? size;? // 鏈表的每一個(gè)節(jié)點(diǎn)實(shí)質(zhì)上是一個(gè)數(shù)組盹靴,但數(shù)組元素的類型是不確定的炸茧,由size表示每一個(gè)數(shù)組元素能夠存儲(chǔ)的最大值
? ? ngx_uint_t? ? ? ? nalloc; // 表示每一個(gè)ngx_list_part_t節(jié)點(diǎn)的容量
? ? ngx_pool_t? ? ? *pool;? // 鏈表中管理內(nèi)存分配的內(nèi)存池對(duì)象
} ngx_list_t;?
給出書中簡圖,一種可能的ngx_list_t鏈表的內(nèi)存分布結(jié)構(gòu)稿静。
對(duì)于鏈表梭冠,Nginx也提供了一組接口:
ngx_list_create接口用于創(chuàng)建新的鏈表;
ngx_list_init接口初始化一個(gè)已有鏈表改备;
ngx_list_push接口用于添加新元素控漠。具體情況詳見<ngx_list.c>。
4)動(dòng)態(tài)數(shù)組容器 <ngx_array.h>
typedef struct {
? ? void? ? ? ? *elts;? // 指向數(shù)組起始地址
? ? ngx_uint_t? nelts;? // 表示數(shù)組中已經(jīng)使用多少個(gè)元素绍妨,其值 <= ngx_list_t中的nalloc
? ? size_t? ? ? size;? // 一個(gè)數(shù)組元素能夠存儲(chǔ)的最大值
? ? ngx_uint_t? nalloc; // 當(dāng)nelts增長到達(dá)nalloc 時(shí)析苫,如果再往此數(shù)組中存儲(chǔ)元素蜕猫,則會(huì)引發(fā)數(shù)組的擴(kuò)容肖方。
? ? ? ? ? ? // 數(shù)組的容量將會(huì)擴(kuò)展到原有容量的2倍大小掰茶。實(shí)際上是分配新的一塊內(nèi)存肃叶,
? ? ? ? ? ? // 新的一塊內(nèi)存的大小是原有內(nèi)存大小的2倍滨攻。原有的數(shù)據(jù)會(huì)被拷貝到新的一塊內(nèi)存中钧舌。
? ? ngx_pool_t? *pool;? // 管理內(nèi)存分配的內(nèi)存池對(duì)象
} ngx_array_t;
基本上跟鏈表容器的節(jié)點(diǎn)元素一致禁熏,接口也類似垦巴,具體詳情見<ngx_array.c>媳搪。
ngx_array_t容器具備以下三個(gè)優(yōu)點(diǎn):
訪問速度快;
允許元素個(gè)數(shù)具備不確定性骤宣;
負(fù)責(zé)元素占用內(nèi)存的分配秦爆,這些內(nèi)存將由內(nèi)存池統(tǒng)一管理;
畫上書中圖描述下此結(jié)構(gòu)體及使用方法:
5)緩沖區(qū) <ngx_buf.h>
緩沖區(qū)ngx_buf_t是Nginx處理大數(shù)據(jù)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)憔披,它既應(yīng)用于內(nèi)存數(shù)據(jù)也應(yīng)用于磁盤數(shù)據(jù)等限。
typedef struct ngx_buf_s? ngx_buf_t;
typedef void *? ? ? ? ? ? ngx_buf_tag_t;
struct ngx_buf_s {
? ? /* 表示從此為止開始處理內(nèi)存數(shù)據(jù)爸吮,同一個(gè)ngx_buf_t可能被多次反復(fù)處理 */
? ? u_char? ? ? ? ? *pos;
? ? /* Nginx有效處理的內(nèi)存結(jié)束地址 */
? ? u_char? ? ? ? ? *last;
? ? /* 處理文件時(shí),含義與pos望门、last相同 */
? ? off_t? ? ? ? ? ? file_pos;
? ? off_t? ? ? ? ? ? file_last;
? ? /* 如果ngx_buf_t緩沖區(qū)用于內(nèi)存形娇,這個(gè)則指向buf起始地址與尾地址...那上面兩字段毛意思,混亂中... */
? ? u_char? ? ? ? ? *start;? ? ? ? /* start of buffer */
? ? u_char? ? ? ? ? *end;? ? ? ? ? /* end of buffer */
? ? /* 表示當(dāng)前緩沖區(qū)類型 */
? ? ngx_buf_tag_t? ? tag;
? ? /* 引用的文件 */
? ? ngx_file_t? ? ? *file;
? ? /* 當(dāng)前緩沖區(qū)的影子緩沖區(qū)(筆記:很少用到筹误,不建議使用) */
? ? ngx_buf_t? ? ? *shadow;
? ? /* the buf's content could be changed */
? ? /* 源碼中有英文注釋桐早,翻譯為中文...
? ? * 以下均為標(biāo)志位,且其值置1的意義
? ? */
? ? /* 臨時(shí)內(nèi)存標(biāo)志位厨剪,表示數(shù)據(jù)在內(nèi)存中哄酝,可修改 */
? ? unsigned? ? ? ? temporary:1;
? ? /*
? ? * the buf's content is in a memory cache or in a read only memory
? ? * and must not be changed
? ? */
? ? /* 表示數(shù)據(jù)在內(nèi)存中,且不能被修改 */
? ? unsigned? ? ? ? memory:1;
? ? /* the buf's content is mmap()ed and must not be changed */
? ? /* 表示內(nèi)存是用mmap系統(tǒng)調(diào)用映射過來丽惶,不可被修改 */
? ? unsigned? ? ? ? mmap:1;
/* 表示可回收 */
? ? unsigned? ? ? ? recycled:1;
? ? /* buf緩沖區(qū)處理的是文件炫七,不是內(nèi)存 */
? ? unsigned? ? ? ? in_file:1;
? ? /* 需要執(zhí)行flush操作 */
? ? unsigned? ? ? ? flush:1;
? ? /* 使用同步方式(可能阻塞Nginx進(jìn)程,謹(jǐn)慎使用) */
? ? unsigned? ? ? ? sync:1;
? ? /* ngx_buf_t可由ngx_chain_t串聯(lián)钾唬,此標(biāo)志位表示當(dāng)前是最后一塊待處理的緩沖區(qū) */
? ? unsigned? ? ? ? last_buf:1;
? ? /* 表示是ngx_chain_t中最后一塊緩沖區(qū) */
? ? unsigned? ? ? ? last_in_chain:1;
/* 配合影子緩沖區(qū)使用万哪,表示最后一個(gè)影子緩沖區(qū) */
? ? unsigned? ? ? ? last_shadow:1;
? ? /* 表示當(dāng)親緩沖區(qū)屬于臨時(shí)文件 */
? ? unsigned? ? ? ? temp_file:1;
? ? /* STUB */ int? num;
};
ngx_buf_t是一種基本的數(shù)據(jù)結(jié)構(gòu),本質(zhì)上提供的僅僅是一些指針成員和標(biāo)志位抡秆。如果我們自定義一個(gè)ngx_buf_t結(jié)構(gòu)奕巍,則應(yīng)該根據(jù)業(yè)務(wù)需求自行定義。
5)緩沖區(qū)鏈表 <ngx_buf.h>
typedef struct ngx_chain_s? ? ? ngx_chain_t;? ? <ngx_core.h>
struct ngx_chain_s {? ? ? ? ? ? ? ? ? ? ? ? ? ? <ngx_buf.h>
? ? ngx_buf_t? ? *buf;? // 指向當(dāng)前緩沖區(qū)
? ? ngx_chain_t? *next; // 指向下一個(gè)儒士,如果是最后一個(gè)ngx_chain_t的止,必須置NULL
};
這個(gè)是與ngx_buf_t配合使用的鏈表結(jié)構(gòu)。摘下博文《Nginx模塊開發(fā)入門》簡圖:
總結(jié)
暫時(shí)沒法總結(jié)着撩。诅福。還沒體會(huì)這些數(shù)據(jù)的好處。對(duì)那個(gè)str_list_t的設(shè)計(jì)拖叙,比較喜歡氓润。
主要參考
《深入理解Nginx》
《Nginx從入門到精通》
《Nginx模塊開發(fā)入門》
---------------------
作者:時(shí)間文盲
來源:CSDN
原文:https://blog.csdn.net/fzy0201/article/details/17512119
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請(qǐng)附上博文鏈接薯鳍!