nginx源码初读(4)--让烦恼从数据结构开始(ngx_str)

本文介绍了nginx中的ngx_str_t结构,它不以''结尾,通过长度和数据指针表示字符串。使用ngx_str_t可以减少内存分配,提高效率。在操作时应注意不要直接用C库的字符串函数,而是使用nginx提供的API。文章讨论了在必须使用C库函数时的解决方案,并列出了一系列ngx_str_t相关的操作函数。
摘要由CSDN通过智能技术生成

nginx作者定义的ngx_str_t中,字符串并不是以传统c的’\0’结尾的,使用了长度len配合data来表示一个数据段。所以我们要尽量使用nginx自带的api进行操作,如果没有自带,那就自己写一个api来进行相关操作,而不要随便使用c自带的字符串处理函数,那样很可能会导致内存越界,而且从原则上来说,这是违规行为。

看看ngx_str_t被定义成了什么:

typedef struct {
    size_t      len;          // 字符数据的长度
    u_char     *data;         // 存储的字符数据
} ngx_str_t;

这样做自然是有道理的,尤其在这个内存占用十分“小气”的nginx里。首先,通过长度来表示字符串长度,降低了长度计算次数。其次,nginx可以重复引用一段字符串内存,data可以指向任意内存,长度表示结束,而不用去copy一份自己的字符串(因为如果要以’\0’结束,而不能更改原字符串,所以势必要copy一段字符串)。这样做减少了很多不必要的内存分配和占用,有效的降低了内存使用量和长度的计算次数。
例如,如果用户请求”GET /test?a=1 http/1.1\r\n”存储在内存0x1d0b0000,这时只需要把r->method_name设置为{ len=3, data=0x1d0b0000}就可以表示方法名”GET”,而不需要单独为method_name再分配内存冗余的存储字符串。

由以上特性可知,我们在nginx中,必须谨慎的修改字符串,需要认真考虑修改后是否会对其它引用造成影响。
如果非要使用libc的函数处理字符串,有两个方案:
1. copy到一个新的buffer里,加上’\0’
2. 把要使用的部分后一位改成0,使用完再改回来(要确定改了后面的东西不会有不良反应0.0)

赋值和初始化操作:

#define ngx_string(str)     { sizeof(str) - 1, (u_char *) str }
/* 使用sizeof将一个传统字符串转换为nginx专用形式,因为使用了sizeof,所以str必须为常量
 * 在传统c标准中只能用于做初始化时的赋值操作,普通的赋值是编译错误的(结构体的赋值操作)
 * 在C99标准中,可以这样来赋值:str=(ngx_str_t)ngx_string("hello world")
 */

#define ngx_null_string     { 0, NULL }
/* 用法同ngx_string,用于将字符串初始化为空 */

#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
/* 这两个函数就是直接调用的,用来给str赋值和重置的,str类型要求是指针,text必须为常量 
 * 这两个函数有一点要注意,因为它们是两个语句,并且没有用括号括住,所以在if等其中要用时要括住
   其实保持良好的习惯就ok,碰到if-else不管是不是单句都括住
 */

大小写转换函数:

#define ngx_tolower(c)      (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define ngx_toupper(c)      (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
/* 通过三元表达式实现字母的大小写转换 */

void
ngx_strlow(u_char *dst, u_char *src, size_t n)
{
    /* 将src的前n个字符转换成小写存放在dst字符串当中,需保证dst指向空间大于等于n且可写。*/
    while (n) {
        *dst = ngx_tolower(*src);
        dst++;
        src++;
        n--;
    }
}
/* 如果想要改变原字符串前n个字母为小写,可以ngx_strlow(str, str, n) */

字符串比较函数:

#define ngx_strncmp(s1, s2, n)  strncmp((const char *) s1, (const char *) s2, n)
/* 字符串比较前n个字符,调用了libc的函数,因为只要指定了n就没问题,注意参数类型是char*不是ngx_str */
#define ngx_strcmp(s1, s2)  strcmp((const char *) s1, (const char *) s2)
/* if (ngx_strcmp(var[i].data, "TZ") == 0
               || ngx_strncmp(var[i].data, "TZ=", 3) == 0) {
       goto tz_found;
   }
 */

ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2);
ngx_i
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值