nginx-nginx數據結構

 本篇文章主要記錄說明使用nginx時,開闢一個簡單http模塊的時序圖,還有nginx中封裝的數據結構及其處理函數。

 1.如何開發一個充滿異步調用,無阻塞的http模塊?

 首先,我們需要把程序嵌如到nginx中(最終變異處的二進制程序nginx要包含我們的代碼)。

 然後,這個http模塊要能介入到處理流程中。

 在正式請求處理時,還要可以獲取nginx框架定義的數據結構,解析後的用戶請求信息

 業務執行完畢後,則要考慮發送響應給用戶(包括將磁盤中的文件以http包體的形式發送給用戶)


我們都是討論C/C++語言來進行編寫,雖然nginx官方不倡導,本文章不討論各個核心模塊如何配合工作。


 2.關於http模塊的調用。

  1.首先nginx是master和多個worker進程的組合,worket進程會在一個for循環語句例反覆調用時間模塊檢測網絡事件,即檢測到TCP請求(接收到SYN包),將會爲它建立TCP連接。

  2.成功建立連接後根據nginx.conf文件中的配置會交由http框架處理。

  ps:http框架會試圖接收完整的HTTP頭部,並在接收到完整的http頭部後將請求的uri和nginx.conf裏的location配置項的匹配來決定如何分發。

  3.處理結束後會調用過濾模塊,然後根據配置文件決定自己的行爲。

 時序圖:

    wKiom1e7wK7wTg9VAAEnwBDVnR8861.png ps:需要注意HTTP框架到具體http模塊間數據流的傳遞,還有之間的協同,以後會寫到。


模塊命名爲:ngx_http_mytest_module.c


下面進入正題,所以下nginx中封裝的數據類型還有數據結構

 以下都爲linux操作系統下的解釋:

 1.×××的封裝:

 typedef intptr_t ngx_int_t; //代表int
 typedef uintptr_t ngx_uint_t; //代表unsinged int


 2.數據結構:

 1.字符串

//字符串的封裝。其中data不是普通的字符串,很有可能不以‘0’結尾。必須配合len
  typedef struct{
      size_t len;
      u_char *data;   
 }ngx_str_t;  
 //用於字符串的比較函數,因爲未必有0,所以必須用ngx_strncmp比較
 #define ngx_strncmp(s1,s2,n) strncmp((const char *)s1,(const char *)s2,n)

 2.鏈表容器:

 

//這裏封裝的鏈表容器使用是很頻繁,比如http頭部就是使用這個數據結構來存儲的。
    typedef struct ngx_list_part_s ngx_list_part_t;
    
    struct ngx_list_part_s
    {
        void            *elts;//數組的起始地址
        ngx_uint_t      nelts; //已經存在多少個元素,必須小於nalloc
        ngx_list_part_t *next; //下一個地址
    }
    
    typedef ngx_list_part_s
    {
        ngx_list_part_t *last;    //鏈表最後一個元素
        ngx_list_part_t part; //鏈表第一個數組元素
        size_t          size;    //每一個數組元素佔用空間大小
        ngx_uint_t      nalloc;    //數組可以存儲多少個數據
        ngx_pool_t      *poll;    //nginx內存池的對象。
    }ngx_list_t;
    
    //下面是封裝的ngx_list_t的函數借口
    ngx_list_t *ngx_list_create(ngx_pool_t *pool,ngx_uint_t n,size_t size);//創建
    //返回創建鏈表地址。
    static ngx_inline ngx_int_t 
    ngx_list_init(ngx_list_t,ngx_pool_t *pool,ngx_uint_t n,size_t size); //初始化
    //返回NGX_OK,    NGX_ERROR;
    void *ngx_list_push(ngx_list_t *list);//添加元素、
    
    //遍歷鏈表
    ngx_list_part_t *part = &testlist.part;
    ngx_str_t = part->elts;
    for(i = 0;;i++)
    {
        if(i >= part->nelts)
        {
            if(part->next = NULL)
                break;
            part = part->next;
            header = part->elts;
            i = 0 ;
        }
        printf("%*s\n",str[i].len,str[i].data);
    }

 3.key/value (用於存儲http頭部信息)

 

    typedef struct
    {
        ngx_uint_t hash;
        ngx_str_t key;
        ngx_str_t value;
        u_char*   lowcase_key; //全是小寫的key字符串。
    }ngax_table_elt_t;

 4.緩衝區的數據結構

typedef struct ngx_buf_s ngx_buf_t;
typedef void *           ngx_buf_tag_t;
struct  ngx_buf_s{
    u_char *pos;    //數據處理的開始位置;
    u_char *last;    //數據處理的結束位置;
    off_t     file_pos; //處理文件的文件開始位置
    off_t    file_last;    //處理文件的文件結束位置
    u_char    *start;    //如果ngx_buf_t用於內存,那麼指向這個內存的起始地址
    u_char    *end;    //緩衝區內存的末尾
    ngx_buf_tag_t tag;    //緩衝區類型
    ngx_file_t    *file;    //引用的文件
    ngx_buf_t    *shadow;    //影子緩衝區,很少用,設計複雜,簡單理解爲多個指向同一塊內存
    unsigned    temporary:1;    //臨時內存標誌位,1表示這段內存可以修改
    unsigned    memory:1;    //標誌位,爲1表示數據在內存中且內存不可以修改
    unsigned    mmap:1;    //1表示這頓啊內存用mmap系統調用映射過來的,不可以被修改
    unsigned    recycled:1;    //1表示可以回收
    unsigned    in_file:1;    //1表示這段緩衝區處理的是文件而不是內存
    unsigned    flush:1;    //1表示需要執行flush操作
    unsigned    sync:1;    //是否需要使用同步方式
    unsigned    last_buf:1;    //表示是否爲最後一塊緩衝區
    unsigned    last_in_chain:1;    //表示是否是ngx_chain_t中的最後一塊緩衝區
    unsigned    last_shadow:1;    //是否是最後一個影子緩衝區,與shadow域配合使用。不建議使用
    unsigned    temp_file:1;    //表示當前緩衝去是否是臨時文件
}

5.ngx_chain_t(與ngx_buf_t配合使用,存儲向用戶發送的HTTP包體,結尾設置爲null)

typedef struct ngx_chain_s    ngx_chain_t;
struct ngx_chain_s{
    ngx_buf_t *buf;
    ngx_chain_t *next;
}


以上就是nginx的數據結構。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章