nginx源码分析三----高级数据结构

一、 与框架相关

ngx_cycle_t

 struct ngx_cycle_s {
    //保存存储所有模块的配置项的结构体指针
    //之所以是4级指针,是因为conf_ctx首先是一个数组
    //然后存储的元素是指针,该指针又指向另外一个指针数组
    void                  ****conf_ctx;  
    //内存池
    ngx_pool_t               *pool;

    /* 在还没有执行ngx_init_cycle之前(即没有解析配置项)
     * 若此时需要输出日志,就暂时用log,它会直接将信息输出到屏幕
     * 当解析了配置项之后,会根据nginx.conf配置文件中的配置构建出要求的日志文件并将log重新赋值
     */
    ngx_log_t                *log;

    ngx_log_t                 new_log;

    /* files保存所有ngx_connection_t的指针组成的数组 */
    ngx_connection_t        **files;
    /* 可用的连接池 */
    ngx_connection_t         *free_connections;
    /* 空闲连接的个数 */
    ngx_uint_t                free_connection_n;

    /* 双向链表, 存储的元素类型是ngx_connection_t, 代表可重复使用的连接队列 */
    ngx_queue_t               reusable_connections_queue;

    /* 动态数组, 存储类型为ngx_listening_t成员, 存储着监听的端口等信息
    ngx_array_t               listening;
    /* 动态数组, 保存nginx所有需要操作的目录, 如果系统中不存在这个目录, 则需要创建
     * 若创建不成功, nginx启动会失败(比如没有权限什么的,所以master进程最好属于root)
     */
    ngx_array_t               pathes;

    /* 单链表, 存储类型为ngx_open_file_t结构体
     * 它表示nginx已经打开的所有文件
     * 由感兴趣的模块向其中添加文件路径名
     * 然后在ngx_init_cycle函数中打开
     */
    ngx_list_t                open_files;

    /* 单链表, 存储类型为ngx_shm_zone_t结构体
     * 每个元素表示一块共享内存
     */
    ngx_list_t                shared_memory;

    /* 所有连接对象的总数 */
    ngx_uint_t                connection_n;
    /* files数组里元素的总数
    ngx_uint_t                files_n;

    /* 指向所有连接对象 */
    ngx_connection_t         *connections;
    /* 指向所有读事件 */
    ngx_event_t              *read_events;
    /* 指向所有写事件 */
    ngx_event_t              *write_events;

    /* 在调用ngx_init_cycle之前,需要一个ngx_cycle_t临时变量来存储一些变量
     * 调用ngx_init_cycle会将该临时变量传入
     * old_cycle就负责保存这个临时变量
    ngx_cycle_t              *old_cycle;

    //配置文件相对安装目录的相对路径名
    ngx_str_t                 conf_file;
    //需要特殊处理的在命令行携带的参数
    ngx_str_t                 conf_param;
    //配置文件所在目录的路径
    ngx_str_t                 conf_prefix;
    //安装目录的路径
    ngx_str_t                 prefix;
    //文件锁名称
    ngx_str_t                 lock_file;
    //主机名(通过gethostname系统调用获取)
    ngx_str_t                 hostname;
};

二、与配置相关

ngx_conf_t

描述: 该结构体用于Nginx在解析配置文件时描述每个指令的属性,也是Nginx程序中非常重要的一个数据结构
位置:ngx_conf_file.h

    char                 *name;    //指令名
    ngx_array_t          *args;    //指令的参数
 
    ngx_cycle_t          *cycle;
    ngx_pool_t           *pool;
    ngx_pool_t           *temp_pool;
    ngx_conf_file_t      *conf_file;   //存放nginx配置文件的相关信息
    ngx_log_t            *log;

    void                 *ctx;          //描述指令的上下文
    ngx_uint_t            module_type;      // 支持该指令的模块的类型,core、http、event和mail中的一种。
    ngx_uint_t            cmd_type;        //指令的类型

    ngx_conf_handler_pt   handler;        //指令对应的处理函数
    void                 *handler_conf;
};

说明: 在解析配置文件时,每解析一个指令,都会生成一个ngx_conf_t结构体,并保存该指令对应的参数,上下文信息,以及对应的handler处理函数。

ngx_http_conf_ctx_t

描述 : nginx启动时解析配置文件nginx.conf,当发现http块时,会依次调用所有http模块的create_main_conf,create_srv_conf,create_loc_conf方法,这些方法都是用来创建各个模块存储自身配置项的结构体。 nginx会将这些结构体的地址指针存放在main_conf,srv_conf,loc_conf的成员里。
位置:ngx_http.c

struct ngx_http_conf_ctx_t {
    void **main_conf;
    void **srv_conf;
    void **loc_conf;
}

ngx_http_upstream_main_conf_t

作用:存储main段upstream的相关配置
位置:ngx_http_upstream_t

typedef struct {
    ngx_hash_t                       headers_in_hash;   //其他模块配置的hash头部信息
    ngx_array_t                       upstreams;            //每一个upstream都存储upstreams数组里。每个upstream都对应一个ngx_http_upstream_srv_conf_t 结构体。
                                             /* ngx_http_upstream_srv_conf_t */
} ngx_http_upstream_main_conf_t;

ngx_http_upstream_srv_conf_t

作用 : 存储单个upstream的配置
位置:ngx_http_upstream_t

struct ngx_http_upstream_srv_conf_s {
    ngx_http_upstream_peer_t         peer;
    void                           **srv_conf;

    ngx_array_t                     *servers;  /* ngx_http_upstream_server_t */

    ngx_uint_t                       flags;
    ngx_str_t                        host;
    u_char                          *file_name;
    ngx_uint_t                       line;
    in_port_t                        port;
    ngx_uint_t                       no_port;  /* unsigned no_port:1 */

#if (NGX_HTTP_UPSTREAM_ZONE)
    ngx_shm_zone_t                  *shm_zone;
#endif
};

三 、与模块相关

ngx_module_t

struct ngx_module_t {
    /*    当前模块在这一类模块中的位置  */
    ngx_uint_t ctx_index  
    /*  当前模块在所有模块中的位置  */
    ngx_uint_t index
    /* 模块的上下文结构体,如果是HTTP模块,这ctx指向ngx_http_module_t结构体*/
    void *ctx
    /* 模块支持的配置指令 */
    ngx_command_t *commands
}

ngx_http_module_t

struct ngx_http_module_t {
    preconfiguration
    postconfiguration
    create_main_conf
    init_main_conf
    create_srv_conf
    create_loc_conf
    merge_srv_conf
    merge_loc_conf
}

ngx_command_t

struct ngx_command_s {
    ngx_str_t             name;   //指令名称
    ngx_uint_t            type;   // 指令能出现的位置
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);   //调用set方法处理配置项的参数
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

ngx_core_conf_t : core模块存储配置项的结构体

    

ngx_process_t:用来记录每个worker子进程的基本信息,Nginx使用一个全局数组保存所有产生的子进程,这就是近程池ngx_processes,这个数组是静态分配的,不能动态增长,Nginx只支持1024个子进程(也就是worker进程),这远大于目前主流计算机CPU核心数量,足够用了。

typedef struct {
  //进程的id号
  ngx_pid_t pid;
  //通过waitpid系统调用获取到的进程状态
  int status;
  //通过socketpair系统调用产生的用于进程间通信的一对socket,用于相互通信。
  ngx_socket_t channel[2];
  //子进程的工作循环
  ngx_spawn_proc_pt proc;
  //proc的第二个参数,可能需要传入一些数据
  void *data;
  //进程名称
  char *name;

  //一些标识位
  //为1时代表需要重新生成子进程
  unsigned respawn : 1;
  //为1代表需要生成子进程
  unsigned just_spawn : 1;
  //为1代表需要进行父、子进程分离
  unsigned detached : 1;
  //为1代表进程正在退出
  unsigned exiting : 1;
  //为1代表进程已经退出了
  unsigned exited : 1;
} ngx_process_t;

ngx_connection_t:nginx的连接池

四 与请求相关

ngx_http_request_t

描述::nginx的每个http请求都对应这个这样一个结构体
位置: ngx_http_request.h

struct ngx_http_request_s {
    uint32_t                          signature;         /* "HTTP" */

    ngx_connection_t                 *connection;

    void                            **ctx;     //保存所有http模块上下文结构体的指针
    void                            **main_conf;
    void                            **srv_conf;
    void                            **loc_conf;

    ngx_http_event_handler_pt         read_event_handler;
    ngx_http_event_handler_pt         write_event_handler;

#if (NGX_HTTP_CACHE)
    ngx_http_cache_t                 *cache;
#endif

    ngx_http_upstream_t              *upstream;
    ngx_array_t                      *upstream_states;
                                         /* of ngx_http_upstream_state_t */

    ngx_pool_t                       *pool;              //请求内存池
    ngx_buf_t                        *header_in;        // 未被nginx解析的头部,主要是那些非RFC2616标准的头部,实际上,header_in就是接受http头部的缓冲区。
    
    ngx_http_headers_in_t             headers_in;        // 存储解析过的http头部信息 
    ngx_http_headers_out_t            headers_out;

    ngx_http_request_body_t          *request_body;

    time_t                            lingering_time;
    time_t                            start_sec;
    ngx_msec_t                        start_msec;

    ngx_uint_t                        method;
    ngx_uint_t                        http_version;

    ngx_str_t                         request_line;
    ngx_str_t                         uri;
    ngx_str_t                         args;
    ngx_str_t                         exten;
    ngx_str_t                         unparsed_uri;

    ngx_str_t                         method_name;
    ngx_str_t                         http_protocol;

    ngx_chain_t                      *out;
    ngx_http_request_t               *main;
    ngx_http_request_t               *parent;
    ngx_http_postponed_request_t     *postponed;
    ngx_http_post_subrequest_t       *post_subrequest;
    ngx_http_posted_request_t        *posted_requests;

    ngx_int_t                         phase_handler;
    ngx_http_handler_pt               content_handler;
    ngx_uint_t                        access_code;

    ngx_http_variable_value_t        *variables;

#if (NGX_PCRE)
    ngx_uint_t                        ncaptures;
    int                              *captures;
    u_char                           *captures_data;
#endif

    size_t                            limit_rate;
    size_t                            limit_rate_after;

    /* used to learn the Apache compatible response length without a header */
    size_t                            header_size;

    off_t                             request_length;

    ngx_uint_t                        err_status;

    ngx_http_connection_t            *http_connection;
    ngx_http_v2_stream_t             *stream;

    ngx_http_log_handler_pt           log_handler;

    ngx_http_cleanup_t               *cleanup;

    unsigned                          count:16;
    unsigned                          subrequests:8;
    unsigned                          blocked:8;

    unsigned                          aio:1;

    unsigned                          http_state:4;

    /* URI with "/." and on Win32 with "//" */
    unsigned                          complex_uri:1;

    /* URI with "%" */
    unsigned                          quoted_uri:1;

    /* URI with "+" */
    unsigned                          plus_in_uri:1;

    /* URI with " " */
    unsigned                          space_in_uri:1;

    unsigned                          invalid_header:1;

    unsigned                          add_uri_to_alias:1;
    unsigned                          valid_location:1;
    unsigned                          valid_unparsed_uri:1;
    unsigned                          uri_changed:1;
    unsigned                          uri_changes:4;

    unsigned                          request_body_in_single_buf:1;
    unsigned                          request_body_in_file_only:1;
    unsigned                          request_body_in_persistent_file:1;
    unsigned                          request_body_in_clean_file:1;
    unsigned                          request_body_file_group_access:1;
    unsigned                          request_body_file_log_level:3;
    unsigned                          request_body_no_buffering:1;

    unsigned                          subrequest_in_memory:1;
    unsigned                          waited:1;

#if (NGX_HTTP_CACHE)
    unsigned                          cached:1;
#endif

#if (NGX_HTTP_GZIP)
    unsigned                          gzip_tested:1;
    unsigned                          gzip_ok:1;
    unsigned                          gzip_vary:1;
#endif

    unsigned                          proxy:1;
    unsigned                          bypass_cache:1;
    unsigned                          no_cache:1;

    /*
     * instead of using the request context data in
     * ngx_http_limit_conn_module and ngx_http_limit_req_module
     * we use the single bits in the request structure
     */
    unsigned                          limit_conn_set:1;
    unsigned                          limit_req_set:1;

#if 0
    unsigned                          cacheable:1;
#endif

    unsigned                          pipeline:1;
    unsigned                          chunked:1;
    unsigned                          header_only:1;
    unsigned                          expect_trailers:1;
    unsigned                          keepalive:1;
    unsigned                          lingering_close:1;
    unsigned                          discard_body:1;
    unsigned                          reading_body:1;
    unsigned                          internal:1;
    unsigned                          error_page:1;
    unsigned                          filter_finalize:1;
    unsigned                          post_action:1;
    unsigned                          request_complete:1;
    unsigned                          request_output:1;
    unsigned                          header_sent:1;
    unsigned                          expect_tested:1;
    unsigned                          root_tested:1;
    unsigned                          done:1;
    unsigned                          logged:1;

    unsigned                          buffered:4;

    unsigned                          main_filter_need_in_memory:1;
    unsigned                          filter_need_in_memory:1;
    unsigned                          filter_need_temporary:1;
    unsigned                          preserve_body:1;
    unsigned                          allow_ranges:1;
    unsigned                          subrequest_ranges:1;
    unsigned                          single_range:1;
    unsigned                          disable_not_modified:1;
    unsigned                          stat_reading:1;
    unsigned                          stat_writing:1;
    unsigned                          stat_processing:1;

    unsigned                          background:1;
    unsigned                          health_check:1;

    /* used to parse HTTP headers */

    ngx_uint_t                        state;

    ngx_uint_t                        header_hash;
    ngx_uint_t                        lowcase_index;
    u_char                            lowcase_header[NGX_HTTP_LC_HEADER_LEN];

    u_char                           *header_name_start;
    u_char                           *header_name_end;
    u_char                           *header_start;
    u_char                           *header_end;

    /*
     * a memory that can be reused after parsing a request line
     * via ngx_http_ephemeral_t
     */

    u_char                           *uri_start;
    u_char                           *uri_end;
    u_char                           *uri_ext;
    u_char                           *args_start;
    u_char                           *request_start;
    u_char                           *request_end;
    u_char                           *method_end;
    u_char                           *schema_start;
    u_char                           *schema_end;
    u_char                           *host_start;
    u_char                           *host_end;
    u_char                           *port_start;
    u_char                           *port_end;

    unsigned                          http_minor:16;
    unsigned                          http_major:16;
};

说明:
1 ctx成员保存着每一个http模块上下文结构体的指针,http框架并不关心请求的上下文信息, 每个请求自己维护自己的ctx成员。

ngx_http_header_in_t

描述: ngx_http_request_t的一个成员,用于存储当前请求被解析过的请求头

typedef struct {
    ngx_list_t                        headers;   	// 非标准的HTTP头都存放在headers的链表里,如果要获取,则必须遍历该链表
	
	// 以下的都是标准的http头部,直接访问成员变量就行,如果没有解析到该头部,这对应的ngx_table_elt_t指针为NULL
    ngx_table_elt_t                  *host;
    ngx_table_elt_t                  *connection;
    ngx_table_elt_t                  *if_modified_since;
    ngx_table_elt_t                  *if_unmodified_since;
    ngx_table_elt_t                  *if_match;
    ngx_table_elt_t                  *if_none_match;
    ngx_table_elt_t                  *user_agent;
    ngx_table_elt_t                  *referer;
    ngx_table_elt_t                  *content_length;
    ngx_table_elt_t                  *content_range;
    ngx_table_elt_t                  *content_type;

    ngx_table_elt_t                  *range;
    ngx_table_elt_t                  *if_range;

    ngx_table_elt_t                  *transfer_encoding;
    ngx_table_elt_t                  *expect;
    ngx_table_elt_t                  *upgrade;

#if (NGX_HTTP_GZIP)
    ngx_table_elt_t                  *accept_encoding;
    ngx_table_elt_t                  *via;
#endif

    ngx_table_elt_t                  *authorization;

    ngx_table_elt_t                  *keep_alive;

#if (NGX_HTTP_X_FORWARDED_FOR)
    ngx_array_t                       x_forwarded_for;
#endif

#if (NGX_HTTP_REALIP)
    ngx_table_elt_t                  *x_real_ip;
#endif

#if (NGX_HTTP_HEADERS)
    ngx_table_elt_t                  *accept;
    ngx_table_elt_t                  *accept_language;
#endif

#if (NGX_HTTP_DAV)
    ngx_table_elt_t                  *depth;
    ngx_table_elt_t                  *destination;
    ngx_table_elt_t                  *overwrite;
    ngx_table_elt_t                  *date;
#endif

    ngx_str_t                         user;
    ngx_str_t                         passwd;

    ngx_array_t                       cookies;

    ngx_str_t                         server;
    off_t                             content_length_n;
    time_t                            keep_alive_n;

    unsigned                          connection_type:2;
    unsigned                          chunked:1;
    unsigned                          msie:1;
    unsigned                          msie6:1;
    unsigned                          opera:1;
    unsigned                          gecko:1;
    unsigned                          chrome:1;
    unsigned                          safari:1;
    unsigned                          konqueror:1;
} ngx_http_headers_in_t;

ngx_http_headers_out_t

typedef struct {
//    待发送的HTTP的头部链表,与ngx_http_request_t中headers_in中的headers成员类似。
    ngx_list_t                        headers;
    ngx_list_t                        trailers;

    ngx_uint_t                        status;
    ngx_str_t                         status_line;
    
    // 一下成员(包括ngx_table_elt_t)都是RFC1616定义的标准的http头部,设置之后通过ngx_http_header_filter_module过滤模块可以把他们加到待发送的网络包中
    ngx_table_elt_t                  *server;
    ngx_table_elt_t                  *date;
    ngx_table_elt_t                  *content_length;
    ngx_table_elt_t                  *content_encoding;
    ngx_table_elt_t                  *location;
    ngx_table_elt_t                  *refresh;
    ngx_table_elt_t                  *last_modified;
    ngx_table_elt_t                  *content_range;
    ngx_table_elt_t                  *accept_ranges;
    ngx_table_elt_t                  *www_authenticate;
    ngx_table_elt_t                  *expires;
    ngx_table_elt_t                  *etag;

    ngx_str_t                        *override_charset;

    size_t                            content_type_len;
    ngx_str_t                         content_type;
    ngx_str_t                         charset;
    u_char                           *content_type_lowcase;
    ngx_uint_t                        content_type_hash;

    ngx_array_t                       cache_control;

    off_t                             content_length_n;
    off_t                             content_offset;
    time_t                            date_time;
    time_t                            last_modified_time;
} ngx_http_headers_out_t;

重要的底层函数:

ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
ngx_http_discard_request_body®;
丢弃请求中的包体

字符串相关

   1 字符串比较:ngx_strcmp()与ngx_strcasecmp()    后者不区分大小写
   2 比较字符串前n个字符: ngx_strncmp()与ngx_strncasecmp()
        示例见<深入理解nginx> P97

输入输出相关:

  1 日志
    
  2 标准输出
  

(三) nginx处理http request的流程

image

三个重要的handler函数:
    行handler: ngx_http_process_request_line
                    ngx_http_read_request_header: 读取行
                    ngx_http_parse_request_line: 解析行
        
    头handler:ngx_http_process_request_headers
                    ngx_http_read_request_header: 读取头
                    ngx_http_parse_header_line:解析头
    
    先不读body,读取到两个换行符时,开始处理请求:
    处理请求handler: ngx_http_process_request
                        ngx_http_handler
                            读事件:read_event_handler
                            写事件:write_event_handler = ngx_http_core_run_phases
            
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值