對於乙個web伺服器程式來說,對字串處理的需求是必須的。由於web環境下的各種編碼,也導致了web伺服器程式字串處理的繁雜性。在nginx原始碼中,ngx_string.c 這個檔案就是來應對字串處理的一些原始碼,原始碼中經常的使用到了這裡中的函式,本文對ngx_string.c 進行一些簡單的分析,以方便閱讀其他原始碼。
我們來看它的基本資料結構:
typedef
struct ngx_str_t;
比較明顯的可以看出,ngx_str_t 只是將字串新增了乙個標誌長度的字段,並無其他特殊結構。
再來看它的功能函式的特點,和前面分析記憶體池(pool)中功能管理函式一樣許多函式直接以巨集定義的形式給出,如:
#define ngx_string(str)
初始化ngx_str_t,len中儲存str字串的出去結束符的長度,data中儲存str字串。
#define ngx_tolower(c) (u_char) ((c >= 'a' && c <= 'z') ? (c | 0x20) : c)
如果字元c是大寫字元就將其轉為小寫,直接用位操作進行。(為什麼 |0x20 就能實現?有興趣的把大寫字元用二進位制表示,而後試試就明白了)
#define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2)
比較,s1 和 s2 兩個字串,實質就是呼叫了strcmp。
#define ngx_memzero(buf, n) (void) memset(buf, 0, n)
初始化,buf為0。
等等,這樣的一些巨集定義函式,在這裡就不一一詳細說明了,都比較簡單容易看懂。
接下來就是一些nginx自己編寫的函式了,如:
void ngx_strlow(u_char *dst, u_char * src, size_t n)
}
將字串
src中前
n個字元全部變成小寫,放在
dst中,呼叫的
ngx_tolower
就是前面介紹了的巨集定義的函式,想想如果
dst=src
呢?把本身的字串中前
n個變成小寫。還有
ngx_cpystrn
、ngx_pstrdup
等函式,這部分函式**結構比較清晰易懂,不詳細一一說明了。
再來看,這樣的一組函式:
ngx_sprintf(u_char *buf, const char *fmt, …)
ngx_snprintf(u_char *buf, size_t max, const char *fmt, …)
ngx_slprintf(u_char *buf, u_char *last, const char *fmt, …)
ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
從命名來看,就能略知一二,這些函式是對字串進行特定的標準格式的輸出到buf中。取ngx_sprintf(u_char *buf, const char *fmt, …)來瞧一瞧:
u_char * ngx_cdecl
ngx_sprintf(u_char *buf,
const
char * fmt, ...)
這是c語言標準的不定引數的寫法:
va_list args;
va_start(args, fmt);
p = ngx_vslprintf(buf, (void *) -1, fmt, args);
va_end(args);
可能有不是很了解這種寫法結構的,特別做下說明。va_start 是用來獲取不定引數,實際上就是獲取不定引數記憶體起始位址 放在va_list中,它的第乙個引數為 va_list 儲存位址,第二個引數為 最後乙個確定引數名,具體到ngx_sprintf 這個函式就是,兩個確定引數u_char *buf, const char *fmt
,所以最後乙個就是fmt。接下來將獲取的va_list 和一些引數傳給 ngx_vslprintf
。值得注意下的是 (void *) -1 這種寫法,指的是將整數-1 轉化為空指標位址,實際上就是 0xffffffff(對於32位機)這個 引數幹嘛什麼用呢?這個得看 ngx_vslprintf
。 ngx_vslprintf
的**就比較長了,但是功能很明確就是對於nginx自定義的資料結構進行標準格式化輸出,就像vprintf 一樣。而ngx_sprintf就相當於sprintf 命名應該也是這麼來的。原始碼中的這段注釋也是很明細的告訴我們這點:
/** supported formats:
* %[0][width][x][x]o off_t
* %[0][width]t time_t
* %[0][width][u][x|x]z ssize_t/size_t
* %[0][width][u][x|x]d int/u_int
* %[0][width][u][x|x]l long
* %[0][width|m][u][x|x]i ngx_int_t/ngx_uint_t
* %[0][width][u][x|x]d int32_t/uint32_t
* %[0][width][u][x|x]l int64_t/uint64_t
* %[0][width|m][u][x|x]a ngx_atomic_int_t/ngx_atomic_uint_t
* %[0][width][.width]f double, max valid number fits to %18.15f
* %p ngx_pid_t
* %m ngx_msec_t
* %r rlim_t
* %p void *
* %v ngx_str_t *
* %v ngx_variable_value_t *
* %s null-terminated string
* %*s length and string
* %z '\0'
* %n '\n'
* %c char
* %% %
** reserved:
* %t ptrdiff_t
* %s null-terminated wchar string
* %c wchar*/
那麼引數
0xffffffff
功能呢?來擷取部分
ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
**來看,看到開頭的這句:
while (*fmt && buf < last)
。明白了吧
last
指的就是格式後輸出到
buf中的尾部界定指標,那麼如果
last= 0xffffffff
即代表了
buf < last
永遠成立,也就是說將
fmt
的所有內容格式化後輸出的
buf中去。看完這裡我們也可以知道
ngx_snprintf(u_char *buf, size_t max, const char *fmt, …)
,ngx_slprintf(u_char *buf, u_char *last, const char *fmt, …)
這兩個函式的功用了,乙個是給定
buf的最大值,乙個是給定
buf的界定。為了更為明晰的理解,
ngx_vslprintf
這個函式,我們給出解析
%v 也就是
nginx
中ngx_str_t *
這個結構體的標準格式化輸出過程,的**分析圖,如圖1
所示:圖1 解析 %v 示意圖
而在 case v 中我們可以看到,獲取不定引數中ngx_str_t 的指標,**為va_arg(args,ngx_str_t),然後確定進入buf的長度,拷貝ngx_str_t 中data的字串,最後完成%v的格式化,繼續下面的字元的分析。其他的格式化也是相似的過程,不過由於各個的特殊性而有所不同。
ngx_string.c中還包括了對uft8 編碼、urf的解析等操作,涉及到編碼的規則和一些相關標準,其實現的功能一般都能從其函式命名中得知,原始碼中遇到也能理解一二,本篇對於ngx_string.c簡單分析就到此結束。
nm 命令輸出項解析
0 linux下的nm命令詳解 nm命令的輸出包含三個部分 1 符號值。預設顯示十六進製制,也可以指定 2 符號型別。小寫表示是本地符號,大寫表示全域性符號 external 3 符號名稱。給個例子 00000000 b bss 00000000 d data 00000000 r rdata 00...
nginx日誌解析輸出elasticstack
需求 實時讀取nginx access日誌經過採集,快取,最終匯入到elasticsearch平台進行展示查詢。由於nginx日誌源主機與elasticsearch平台在不同的內網網段內,所以沒有採用通常直接的logstash讀取並解析然後直接輸出到elasticsearch。而是在日誌源執行log...
Top命令輸出資訊解析
在linux下top是乙個最基礎的命令,它可以將當前系統的執行狀況最直觀地告訴使用者。top命令的輸出的資訊很豐富,功能很強大,本篇我就詳細介紹一下它。第一行給出當前伺服器時間,啟動時間,當前登入使用者,以及系統負載情況。需要注意的是linux的系統負載是以1分鐘 3分鐘和15分鐘內的平均值來衡量的...