Nginx 源码分析 一

ngx_cycle_t 分析

struct ngx_cycle_s {  
    void                  ****conf_ctx;  //配置上下文数组(含所有模块)  
    ngx_pool_t               *pool;      //内存池  

    ngx_log_t                *log;       //日志  
    ngx_log_t                 new_log;  

    ngx_connection_t        **files;     //连接文件  
    ngx_connection_t         *free_connections;  //空闲连接  
    ngx_uint_t                free_connection_n; //空闲连接个数  

    ngx_queue_t               reusable_connections_queue;  //再利用连接队列  

    ngx_array_t               listening;     //监听数组  
    ngx_array_t               pathes;        //路径数组  
    ngx_list_t                open_files;    //打开文件链表  
    ngx_list_t                shared_memory; //共享内存链表  

    ngx_uint_t                connection_n;  //连接个数  
    ngx_uint_t                files_n;       //打开文件个数  

    ngx_connection_t         *connections;   //连接  
    ngx_event_t              *read_events;   //读事件  
    ngx_event_t              *write_events;  //写事件  

    ngx_cycle_t              *old_cycle;     //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;     //锁文件  
    ngx_str_t                 hostname;      //主机名  
};

nginx struct

模块初始化

在http/ngxhttp.c文件中,ngxhttpblock函数会依次判断模块类型,如果模块类型为NGXHTTP_MODULE,则调用模块的三个初始化函数。

   for (m = 0; cf->cycle->modules[m]; m++) {
        if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = cf->cycle->modules[m]->ctx;

        mi = cf->cycle->modules[m]->ctx_index;

        if (module->create_main_conf) {

            ctx->main_conf[mi] = module->create_main_conf(cf);
            if (ctx->main_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        if (module->create_srv_conf) {

            ctx->srv_conf[mi] = module->create_srv_conf(cf);
            if (ctx->srv_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        if (module->create_loc_conf) {

            ctx->loc_conf[mi] = module->create_loc_conf(cf);
            if (ctx->loc_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
    }

三个函数原型如下:

typedef struct {  
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);

    void       *(*create_main_conf)(ngx_conf_t *cf);
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);

    void       *(*create_srv_conf)(ngx_conf_t *cf);
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);

    void       *(*create_loc_conf)(ngx_conf_t *cf);
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
  • preconfiguration 在读入配置前调用
  • postconfiguration 在读入配置后调用
  • createmainconf 在创建main配置时调用(比如,用来分配空间和设置默认值)
  • initmainconf 在初始化main配置时调用(比如,把原来的默认值用nginx.conf读到的值来覆盖)
  • initmainconf 在创建server配置时调用
  • mergesrvconf 合并server和main配置时调用
  • createlocconf 创建location配置时调用
  • mergelocconf 合并location和server配置时调用

遍历输出ngxarrayt

typedef struct ngx_array_s  ngx_array_t;  
struct ngx_array_s {  
    void        *elts;  //具体的数据区域的起始地址  
    ngx_uint_t   nelts; //已经存储了的元素数量  
    size_t       size;  //单个元素的大小(字节)  
    ngx_uint_t   nalloc; //数组容量,即数组预先分配的内存大小  
    ngx_pool_t  *pool;  //内存池,用其保存分配此数组的内存池地址。  
};  

static void print_array(ngx_array_t *a);  
static void print_array(ngx_array_t *a)// 遍历输出array  
{  
    printf("-------------------------------\n");  
    ngx_http_upstream_server_t *p = a->elts;  
    size_t i;  
    for(i=0; i < a->nelts; ++i)  
    {  
        printf("%s.\n", (p+i)->name.data);  
    }  
    printf("-------------------------------\n");  
}

Request

Nginx的request是指http请求,涉及到的数据结构为ngxhttprequests,该数据结构贯穿了http请求的整个过程,可以说处理http请求就是操作ngxhttprequestt数据结构。

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

    ngx_connection_t                 *connection; //请求对应的客户端连接

    void                            **ctx; //指向存放所有HTTP模块的上下文结构体的指针数组
    void                            **main_conf; //指向请求对应的存放main级别配置结构体的指针数组
    void                            **srv_conf; //指向请求对应的存放srv级别配置结构体的指针数组
    void                            **loc_conf; //指向请求对应的存放loc级别配置结构体的指针数组

    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; //upstream机制用到的结构体,如果模块是load-balance的话设置这个
    ngx_array_t                      *upstream_states;
                                         /* of ngx_http_upstream_state_t */

    ngx_pool_t                       *pool;
    ngx_buf_t                        *header_in;

    ngx_http_headers_in_t             headers_in;
    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;
    /*
     * 当前请求既可能是用户发来的请求,也可能是派生出的子请求,而main则标识一系列相关的派生子请求的原始请求
     * 可以通过main和当前请求的地址是否相等来判断当前请求是否为用户发来的原始请求
     */
    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;
#if (NGX_HTTP_SPDY)
    ngx_http_spdy_stream_t           *spdy_stream;
#endif

    ngx_http_log_handler_pt           log_handler;

    ngx_http_cleanup_t               *cleanup;

    unsigned                          subrequests:8;
    unsigned                          count: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; //1表示URL发生过rewrite重写
    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                          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; //1表示发送给客户端的HTTP响应头部已经发送
    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                          allow_ranges:1;
    unsigned                          single_range:1;
    unsigned                          disable_not_modified:1;

#if (NGX_STAT_STUB)
    unsigned                          stat_reading:1;
    unsigned                          stat_writing:1;
#endif

    /* used to parse HTTP headers */

    ngx_uint_t                        state; //状态机解析HTTP时使用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;
};

ngx-connection-s

struct ngx_connection_s {  
    //连接未使用时,data用于充当连接池中空闲链表中的next指针。连接使用时由模块而定,HTTP中,data指向ngx_http_request_t  
    void               *data;  
    ngx_event_t        *read;//连接对应的读事件  
    ngx_event_t        *write;//连接对应的写事件  

    ngx_socket_t        fd;//套接字对应的句柄  

    ngx_recv_pt         recv;//直接接收网络字符流的方法  
    ngx_send_pt         send;//直接发送网络字符流的方法  
    ngx_recv_chain_pt   recv_chain;//以链表来接收网络字符流的方法  
    ngx_send_chain_pt   send_chain;//以链表来发送网络字符流的方法  
    //这个连接对应的ngx_listening_t监听对象,此连接由listening监听端口的事件建立  
    ngx_listening_t    *listening;  

    off_t               sent;//这个连接上已发送的字节数  

    ngx_log_t          *log;//日志对象  
       /*内存池。一般在accept一个新的连接时,会创建一个内存池,而在这个连接结束时会销毁内存池。内存池大小是由上面listening成员的pool_size决定的*/  
    ngx_pool_t         *pool;  

    struct sockaddr    *sockaddr;//连接客户端的sockaddr  
    socklen_t           socklen;//sockaddr结构体的长度  
    ngx_str_t           addr_text;//连接客户段字符串形式的IP地址  

#if (NGX_SSL)  
    ngx_ssl_connection_t  *ssl;  
#endif  
    //本机监听端口对应的sockaddr结构体,实际上就是listening监听对象的sockaddr成员  
    struct sockaddr    *local_sockaddr;  

    ngx_buf_t          *buffer;//用户接受、缓存客户端发来的字符流,buffer是由连接内存池分配的,大小自由决定  
    /*用来将当前连接以双向链表元素的形式添加到ngx_cycle_t核心结构体的reuseable_connection_queue双向链表中,表示可以重用的连接*/  
    ngx_queue_t         queue;  
    /*连接使用次数。ngx_connection_t结构体每次建立一条来自客户端的连接,或者主动向后端服务器发起连接时,number都会加1*/  
    ngx_atomic_uint_t   number;  

    ngx_uint_t          requests;//处理的请求次数  
    //缓存中的业务类型。  
    unsigned            buffered:8;  
    //本连接的日志级别,占用3位,取值范围为0~7,但实际只定义了5个值,由ngx_connection_log_error_e枚举表示。  
    unsigned            log_error:3;     /* ngx_connection_log_error_e */  

    unsigned            single_connection:1;//为1时表示独立的连接,为0表示依靠其他连接行为而建立起来的非独立连接  
    unsigned            unexpected_eof:1;//为1表示不期待字符流结束  
    unsigned            timedout:1;//为1表示连接已经超时  
    unsigned            error:1;//为1表示连接处理过程中出现错误  
    unsigned            destroyed:1;//为1表示连接已经销毁  

    unsigned            idle:1;//为1表示连接处于空闲状态,如keepalive两次请求中间的状态  
    unsigned            reusable:1;//为1表示连接可重用,与上面的queue字段对应使用  
    unsigned            close:1;//为1表示连接关闭  

    unsigned            sendfile:1;//为1表示正在将文件中的数据发往连接的另一端  
    /*为1表示只有连接套接字对应的发送缓冲区必须满足最低设置的大小阀值时,事件驱动模块才会分发该事件。这与ngx_handle_write_event方法中的lowat参数是对应的*/  
    unsigned            sndlowat:1;  
    unsigned            tcp_nodelay:2;   /* ngx_connection_tcp_nodelay_e */  
    unsigned            tcp_nopush:2;    /* ngx_connection_tcp_nopush_e */  

#if (NGX_HAVE_IOCP)  
    unsigned            accept_context_updated:1;  
#endif  

#if (NGX_HAVE_AIO_SENDFILE)  
    unsigned            aio_sendfile:1;  
    ngx_buf_t          *busy_sendfile;  
#endif  

#if (NGX_THREADS)  
    ngx_atomic_t        lock;  
#endif  
};