Ningx代码研究(一)

Updated Aug 19, 2009 byRainX1982
   NginxCodeReview  
Ningx代码研究.

 

 

概述

Nginx  ("engine x") 是一个高性能的 HTTP  反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器 
 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的Rambler.ru 站点开发的,它已经在该站点运行超过四年多了。
Igor 将源代码以类BSD许可证的形式发布。自Nginx 发布四年来,Nginx 已经因为它的稳定性、丰富的功能集
、示例配置文件和低系统资源的消耗而闻名了。目前国内各大门户网站已经部署了Nginx
如新浪、网易、腾讯等;国内几个重要的视频分享网站也部署了Nginx,如六房间、酷6等。
新近发现Nginx 技术在国内日趋火热,越来越多的网站开始部署Nginx 

- from http://wiki.nginx.org/NginxChs

我们研究nginx的源代码的动机是为了完成分段反向代理项目的开发,由于分段反向代理的需求要求对web server的并发性很强,并且是给予http协议的基础上进行的, 所以我们选择了使用Nginx的模块的形式进行开发。

我们发现目前学习nginx的例子很少,主要是emiller的模块开发介绍这篇文章, 但是单独研究这篇文章发现很多晦涩难懂的地方,而目前还没有其他更好的文章来对这些地方做解释, 有些东西必须要通过源代码的研读才可以了解的更加清楚,所以我们决定开始进行代码研究计划,以便于更好的完成开发任务

根据目前的状况,我们决定使用最新的稳定版本进行研究,故而选择 0.7.61 版作为调研对象。

http://sysoev.ru/nginx/nginx-0.7.61.tar.gz

研究计划

下面是王晓哲帮助制定的调研计划

  • 学习emiller的文章
  • 熟悉nginx的基本数据结构 1w
  • 了解nginx的core module 的结构和运行机制, 同时参考 event 和 os module 的实现 1w
  • 了解nginx的http core module 的结构和运行机制 1w
  • 学习handler 类型module的编写 2d
  • 学习filter 类型module的编写 2d
  • upstream类型module的编写 1w

参与人员

徐景(rainx), 王晓哲(chaoslawful)

研究文档

学习emiller的文章

http://www.evanmiller.org/nginx-modules-guide.html

熟悉nginx的基本数据结构

nginx 代码的目录结构

解开nginx的代码后,在src目录下发现有如下的几个目录

core  event  http  mail  misc  os

其中 :

  • core : 该目录存放core module的代码,也是nginx服务的入口
  • http : http core module 的代码,nginx作为web/http proxy server运行时的核心模块
  • mail : mail core module 的代码,nginx作为pop3/imap/smtp proxy server运行时的核心模块 ( 不在我们本次研究范围内 )
  • event : nginx 自身对事件处理逻辑的封装
  • os : nginx对各个平台抽象逻辑的封装
  • misc : nginx 的一些utils,定义了test和profiler的一些外围模块的逻辑

为了方便了解整个结构, 我们在src目录下建立了一个子目录,叫做demo,然后根据每个章节内容的不同,分别在demo下建立子目录,存放一些学习时使用的代码,如我们目前的章节是学习基本的数据类型,所以建立basic_types子目录

rainx@rainx-laptop:~/land/nginx-0.7.61/src$ mkdir -p demo/basic_types/

nginx简单的数据类型的表示

在 core/ngx_config.h 目录里面定义了基本的数据类型的映射,大部分都映射到c语言自身的数据类型

typedef intptr_t        ngx_int_t;
typedef uintptr_t       ngx_uint_t;
typedef intptr_t        ngx_flag_t;

其中 ngx_int_t, nginx_flag_t, 都映射为 intptr_t; ngx_uint_t映射为 uintptr_t

这两个类型在/usr/include/stdint.h的定义为:

/* Types for `void *' pointers.  */
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int                intptr_t;
#  define __intptr_t_defined
# endif
typedef unsigned long int       uintptr_t;
#else
# ifndef __intptr_t_defined
typedef int                     intptr_t;
#  define __intptr_t_defined
# endif
typedef unsigned int            uintptr_t;
#endif

所以基本的操作和整形/指针类型的操作类似

建立文件

#include <stdio.h>
#include "../../core/ngx_config.h"

int main()
{
    ngx_uint_t a;
    ngx_int_t b;
    a = 1000;
    b = -1000;
    printf ("%d + %d = %d\n", a, b, a+b);
    return 0;
}

编译测试

gcc -I ../../../objs/ -I ../../os/unix/ basic_types_int.c -o basic_types_int
./basic_types_int
1000 + -1000 = 0

nginx字符串的数据类型的表示

nginx对c语言的字符串类型进行了简单的封装, core/ngx_string.h/c 里面包含这些封装的内容

其中定义了 ngx_str_t ,ngx_keyval_t, ngx_variable_value_t

这几个基础类型的定义如下

typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;


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


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;

可以看出 ngx_str_t 在原有的uchar* 的基础上加入的字符串长度的附加信息, 初始化使用ngx_string宏进行,他的定义为:

#define ngx_string(str)     { sizeof(str) - 1, (u_char *) str }

测试字符串的代码 demo/basic_types/basic_types_str.c

#include <stdio.h>
#include "ngx_config.h"
#include "ngx_conf_file.h"
#include "nginx.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_string.h"

volatile ngx_cycle_t  *ngx_cycle;

void
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
            const char *fmt, ...)
{
}

int main()
{
    u_char* p = NULL;
    ngx_uint_t size;
    ngx_str_t dst;
    ngx_str_t mystr = ngx_string("hello, world !");
    ngx_keyval_t pair = {ngx_string("url"), ngx_string("http://rainx.cn/index.php?test=1")};
    int dst_len  =ngx_base64_encoded_length(mystr.len);
    printf("source length is %d, destination length is %d\n", mystr.len, dst_len );
    p = malloc( ngx_base64_encoded_length(mystr.len) + 1);
    dst.data = p;
    ngx_encode_base64(&dst, &mystr);
    printf("source str is %s\ndestination str is %s\n", mystr.data, dst.data);
    free(p);
    size = pair.value.len + 2 * ngx_escape_uri(NULL, pair.value.data, pair.value.len, NGX_ESCAPE_URI);
    p = malloc (size * sizeof(u_char));
    ngx_escape_uri(p, pair.value.data, pair.value.len, NGX_ESCAPE_URI);
    printf("escaped %s is : %s (%d)\noriginal url size is %d\n", pair.key.data, p, size, pair.value.len);
    free(p);
    return 0;

}

编译运行

gcc  -c -O -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Wunused-function -Wunused-variable -Wunused-value -Werror -g -I ../../../objs/ -I ../../os/unix/ basic_types_str.c -I../../core/ -I../../event/ -I../../os/ -o basic_types_str.o
gcc -o basic_types_str basic_types_str.o ../../../objs/src/core/ngx_{string,palloc}.o ../../../objs/src/os/unix/ngx_alloc.o -lcrypt -lpcre -lcrypto -lz
rainx@rainx-laptop:~/land/nginx-0.7.61/src/demo/basic_types$ ./basic_types_str 
source length is 14, destination length is 20
source str is hello, world !
destination str is aGVsbG8sIHdvcmxkICE=
escaped url is : http://rainx.cn/index.php%3ftest=1 (34)
original url size is 32

core/ngx_string.h/c 中同时也封装了一批字符/字符串处理的函数和宏,他们的使用大多数情况下和c标准库中的类似,只是在内存分配相关的函数中有一定的区别。

比如 u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src); 除了源字符串驻外,还要传入ngx_pool_t的指针作为参数,使用nginx自己的内存分配方式进行内存的分配。

除了标准的字符串操作外, nginx还实现了例如:

// base64 编码/解码函数和宏

#define ngx_base64_encoded_length(len)  (((len + 2) / 3) * 4)
#define ngx_base64_decoded_length(len)  (((len + 3) / 4) * 3)

void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);

//utf-8 编码/解码相关函数

uint32_t ngx_utf8_decode(u_char **p, size_t n);
size_t ngx_utf8_length(u_char *p, size_t n);
u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len);

// urlencode和html实体的编码解码
uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
    ngx_uint_t type);
void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type);
uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size);

等对于http服务有帮助的宏和函数

 

[LINK]http://code.google.com/p/nginxsrp/wiki/NginxCodeReview

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