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

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一个基础的数据结构。后边开发自己模块的时候会大量的使用。

你可能感兴趣的:(nginx,nginx,数据结构)