5.nginx源码分析之数据结构:ngx_string

来源:互联网 发布:淘宝上万宝贝怎么上传 编辑:程序博客网 时间:2024/05/16 19:33

ngx_string

nginx的数据结构设计的非常精巧,高效,学习nginx的数据结构设计可以加深我们对于其后续代码的阅读深度。

nginx的数据结构在源码包的src/core目录中,nginx对应的文件是ngx_string.c和ngx_string.h文件:

[root@rsync core]# ll ngx_string.*-rw-r--r-- 1 1001 1001 43851 Oct 11 11:03 ngx_string.c-rw-r--r-- 1 1001 1001  6550 Oct 11 11:03 ngx_string.h

ngx_string.h

首先我们查看ngx_string.h头文件:

最基本的ngx_str_t定义如下,他有长度和指针两个元素:

typedef struct {    size_t      len;    //字符串长度    u_char     *data;   //data是一个指针,在后续中只是起指示左右} ngx_str_t;

紧接着定义了键值的结构,其实就是包含两个ngx_str_t的结构体:

typedef struct {    ngx_str_t   key;    ngx_str_t   value;} ngx_keyval_t;

紧接着定义了nginx的变量类型,其中有很多枚举代表着不同的状态:

typedef struct {    unsigned    len:28;    unsigned    valid:1;    unsigned    no_cacheable:1;    unsigned    not_found:1;    unsigned    escape:1;    u_char     *data;} ngx_variable_value_t;

nginx为了方便字符串的操作,减少函数调用,使用了很多宏来进行字符串的比较。如下所示:

//下面两个宏是nginx中字符串赋值或者置空时的操作,需要修改ngx_str_t中的长度和指针#define ngx_string(str)     { sizeof(str) - 1, (u_char *) str }    #define ngx_null_string     { 0, NULL }//这个是对标准库的简单封装#define ngx_strncmp(s1, s2, n)  strncmp((const char *) s1, (const char *) s2, n)#define ngx_strcmp(s1, s2)  strcmp((const char *) s1, (const char *) s2)#define ngx_strstr(s1, s2)  strstr((const char *) s1, (const char *) s2)#define ngx_strlen(s)       strlen((const char *) s)#define ngx_strchr(s1, c)   strchr((const char *) s1, (int) c)//内存置位操作#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)#define ngx_memset(buf, c, n)     (void) memset(buf, c, n)

还对格式化的输出进行了封装:

u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...);u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt,    ...);u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args);

关于格式化输出可以去参考可变参函数的实现。nginx支持的格式化输出除了printf的之外,还包含了自己支持额格式:

/* * 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 */

ngx_string.c

在ngx_string.c文件中实现了很多关于字符串的操作,书写的也十分简练:

//不群分大小写的字符串比较ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2){    ngx_uint_t  c1, c2;    for ( ;; ) {        c1 = (ngx_uint_t) *s1++;        c2 = (ngx_uint_t) *s2++;        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;        if (c1 == c2) {            if (c1) {                continue;            }            return 0;        }        return c1 - c2;    }}

更多的接口实现如下所示:

ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n);u_char *ngx_strnstr(u_char *s1, char *s2, size_t n);u_char *ngx_strstrn(u_char *s1, char *s2, size_t n);u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n);u_char *ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n);ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2);ngx_int_t ngx_filename_cmp(u_char *s1, u_char *s2, size_t n);ngx_int_t ngx_atoi(u_char *line, size_t n);ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point);ssize_t ngx_atosz(u_char *line, size_t n);off_t ngx_atoof(u_char *line, size_t n);time_t ngx_atotm(u_char *line, size_t n);ngx_int_t ngx_hextoi(u_char *line, size_t n);u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len);

关于细节可以查看ngx_string.c文件。字符串算是nginx一个基础的数据结构。后边开发自己模块的时候会大量的使用。

1 0