前面描述了nginx系统分析nginx的配置文件,初始化模块相关参数的过程,这里利用nginx监听socket的实现过程,做一次完整的回顾

1、首先,nginx启动的main函数中,会先初始化cycle数据结构

    cycle = ngx_init_cycle(&init_cycle);

2、在初始化cycle中,nginx做了关于生成配置参数项,分析配置文件,初始化配置参数项等工作。当然在完成这些工作后,nginx还在初始化cycle函数中,完成了监听socket的流程

   //生成NGX_CORE_MODULE模块的核心配置项
for (i = ; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_CORE_MODULE) {
continue;
} module = ngx_modules[i]->ctx; if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[ngx_modules[i]->index] = rv;
}
} senv = environ; ngx_memzero(&conf, sizeof(ngx_conf_t));
conf.args = ngx_array_create(pool, , sizeof(ngx_str_t));
if (conf.args == NULL) {
ngx_destroy_pool(pool);
return NULL;
} conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
if (conf.temp_pool == NULL) {
ngx_destroy_pool(pool);
return NULL;
} conf.ctx = cycle->conf_ctx;
conf.cycle = cycle;
conf.pool = pool;
conf.log = log;
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF; #if 0
log->log_level = NGX_LOG_DEBUG_ALL;
#endif if (ngx_conf_param(&conf) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
} //分析配置文件
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
} if (ngx_test_config && !ngx_quiet_mode) {
ngx_log_stderr(, "the configuration file %s syntax is ok",
cycle->conf_file.data);
} //初始化NGX_CORE_MODULE类型模块
for (i = ; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_CORE_MODULE) {
continue;
} module = ngx_modules[i]->ctx; if (module->init_conf) {
if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
== NGX_CONF_ERROR)
{
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
}
}

3、在分析配置文件中,符合下面的流程,首先配置文件格式有下面几种

  a、格式1

X a b;

b、格式2

X{
}

  在分析中X,a,b都会被推进cf->args数组中; 然后分析,所有模块类型是NGX_CORE_MODULE,指令类型包含NGX_MAIN_CONF这种类型的,同时指令的名称和X的名称一致的指令,如果有,则利用这个指令去做参数的设置。 我们看格式2的指令情况,例如X是http,配置文件的分析中,遇到“http {” 时候,会执行 ngx_http_block命令

static ngx_command_t  ngx_http_commands[] = {

    { ngx_string("http"),
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_http_block,
,
,
NULL }, ngx_null_command
}; static ngx_core_module_t ngx_http_module_ctx = {
ngx_string("http"),
NULL,
NULL
}; ngx_module_t ngx_http_module = {
NGX_MODULE_V1,
&ngx_http_module_ctx, /* module context */
ngx_http_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};

4、执行ngx_http_block命令,我们看代码可以知道, ngx_http_module模块会对所有http模块做管理,对于将配置信息分成,main_conf, srv_conf和 loc_conf,我们在前面已经绘制图形表示过,这里不再重复,同时在ngx_http_block命令中,会继续分析配置文件(并非重头开始,而是从"http{" 后面开始)

    /* parse inside the http{} block */

    cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN_CONF;
rv = ngx_conf_parse(cf, NULL);

5、分析的配置信息是http{}内部的参数信息,我们可以知道,http{}内部的参数格式如下

http {
include mime.types; server {
}     # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;     #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #} }

6、我们知道,listen在nginx中用来描述定义的web服务绑定的端口,配置的时候都是放在 server{}中,到这个时候,我们已经知道nginx在分析配置信息中发现“server {”的处理流程了,在NGX_HTTP_MODULE类型模块中,找到指令类型是NGX_HTTP_MAIN_CONF,指令名称是server的指令去执行。我们在ngx_http_core_module中找到了server指令

    { ngx_string("server"),
NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_http_core_server,
,
,
NULL },

7、分析server参数的项使用的是同样的办法,这里不再细述。

    /* parse inside server{} */

    pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF; rv = ngx_conf_parse(cf, NULL);

8、到此,我们基本知道,nginx关于listen参数的定制的实现,是在在NGX_HTTP_MODULE类型模块中,找到指令类型是NGX_HTTP_SRV_CONF,指令名称是listen的指令去执行。 我们在ngx_http_core_module中找到符合要求的指令。

    { ngx_string("listen"),
NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
ngx_http_core_listen,
NGX_HTTP_SRV_CONF_OFFSET,
,
NULL },

9、listen指令的ngx_http_core_listen工作是去设置用户设置的值。

static char *
ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_srv_conf_t *cscf = conf; ngx_str_t *value, size;
ngx_url_t u;
ngx_uint_t n;
ngx_http_listen_opt_t lsopt; cscf->listen = ; value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); u.url = value[];
u.listen = ;
u.default_port = ; //listen可以用url的格式 例如 listen somename:8080;下面是实现过程
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ,
"%s in \"%V\" of the \"listen\" directive",
u.err, &u.url);
} return NGX_CONF_ERROR;
} ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); ngx_memcpy(&lsopt.u.sockaddr, u.sockaddr, u.socklen); lsopt.socklen = u.socklen;
lsopt.backlog = NGX_LISTEN_BACKLOG;
lsopt.rcvbuf = -;
lsopt.sndbuf = -;
#if (NGX_HAVE_SETFIB)
lsopt.setfib = -;
#endif
lsopt.wildcard = u.wildcard;
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
lsopt.ipv6only = ;
#endif (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,
NGX_SOCKADDR_STRLEN, ); for (n = ; n < cf->args->nelts; n++) { } if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) {
return NGX_CONF_OK;
} return NGX_CONF_ERROR;

10、我们可以看见,多个server中,用户定义的端口会被放置在cmcf->ports数组中

ngx_int_t
ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_listen_opt_t *lsopt)
{
in_port_t p;
ngx_uint_t i;
struct sockaddr *sa;
struct sockaddr_in *sin;
ngx_http_conf_port_t *port;
ngx_http_core_main_conf_t *cmcf;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
#endif cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); ...... port = ngx_array_push(cmcf->ports);
if (port == NULL) {
return NGX_ERROR;
} port->family = sa->sa_family;
port->port = p;
port->addrs.elts = NULL; return ngx_http_add_address(cf, cscf, port, lsopt);
}

11、继续第3步开始的ngx_http_block分析,在ngx_http_optimize_servers方法中,我们可以看到,建立了从配置文件分析listen的信息(存储到cmcf->ports结构中),会关联到cycle->listening数组中

 /* optimize the lists of ports, addresses and server names */

    if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
return NGX_CONF_ERROR;
}
static ngx_int_t
ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
{
ngx_uint_t i, last, bind_wildcard;
ngx_listening_t *ls;
ngx_http_port_t *hport;
ngx_http_conf_addr_t *addr; addr = port->addrs.elts;
last = port->addrs.nelts; /*
* If there is a binding to an "*:port" then we need to bind() to
* the "*:port" only and ignore other implicit bindings. The bindings
* have been already sorted: explicit bindings are on the start, then
* implicit bindings go, and wildcard binding is in the end.
*/ if (addr[last - ].opt.wildcard) {
addr[last - ].opt.bind = ;
bind_wildcard = ; } else {
bind_wildcard = ;
} i = ; while (i < last) { if (bind_wildcard && !addr[i].opt.bind) {
i++;
continue;
} ls = ngx_http_add_listening(cf, &addr[i]);
if (ls == NULL) {
return NGX_ERROR;
}
……
}
……
}

12、完成用户定制的分析过程后,在初始化化cycle中,nginx打开了监听的socket

    if (ngx_open_listening_sockets(cycle) != NGX_OK) {
goto failed;
}

Nginx源码研究八:nginx监听socket实现流程的更多相关文章

  1. nginx源码分析:打开监听套接字的流程

    问题源于在分析nginx的源码时,找了半天没有找到nginx是怎么把监听套接字读事件添加到事件循环中的,后经过仔细的分析,终于搞明白,于是记录一下. 在上一篇module机制中介绍了nginx添加mo ...

  2. Nginx源码研究一:NGINX模块启动

    Nginx 是一个轻量级,但是高性能的 HTTP 和 代理 服务器,也是一个 IMAP/POP3/SMTP代理服务器. 它的第一个版本0.1.0是由俄罗斯的工程师Igor Sysoev与2004年10 ...

  3. Nginx源码研究三:Epoll在NGINX中的使用

    Web服务器在面对高并发的情况下,网络的IO一般选择IO复用,像apache选择的Select/poll.Nginx在linux 2.6后选择Epoll做网路IO,提高了WEB服务的并发能力. 在本章 ...

  4. Nginx源码研究七:nginx的location指令分析

    在nginx的配置文件nginx.conf中,我们在配置server的时候,会配置一下location指令,这个location指令是提供给用户来配置对于符合指令的http请求,采用该指令内部的处理方 ...

  5. Nginx源码研究六:NGINX的配置文件分析

    上一篇写到nginx的各个模块的配置信息的存储结构,大体描述了对配置信息的配置项生成,定制,初始化过程.这里重点研究实现定制的过程,所谓实现定制,这里指的是,nginx系统提供使用者定义nginx的配 ...

  6. spring boot 源码赏析之事件监听

    使用spring Boot已经快1年多了,期间一直想点开springboot源码查看,但由于种种原因一直未能如愿(主要是人类的惰性...),今天就拿springboot 的监听事件祭刀. spring ...

  7. wemall app商城源码Android短信监听接收器

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  8. Nginx (一)Windows下编译Nginx源码以及安装 nginx for windows方法步骤

    转载自: http://apps.hi.baidu.com/share/detail/11192699#content Nginx介绍: Nginx ("engine x")是一个 ...

  9. Nginx源码研究五:NGINX的配置信息管理

    配置信息是nginx系统重要的组成部分,配置信息的使用,实际上包含两层,一层是用户针对参数定义了值,例如下面nginx参数文件中的 keepalive_timeout 65,还有一部分是用户没有定义值 ...

随机推荐

  1. 【动态规划】Vijos P1218 数字游戏(NOIP2003普及组)

    题目链接: https://vijos.org/p/1218 题目大意: 一个N个数的环,分成M块,块内的数求和%10,最后每块地值累乘,求最大和最小. n(1≤n≤50)和m(1≤m≤9)太小了可以 ...

  2. CTE Recursion Performance

    CTE全名是Common Table Expression,语法基础请参考MSDN文档:https://msdn.microsoft.com/zh-cn/library/ms175972.aspx. ...

  3. Jenkins 四: 启动关闭以及重启jenkins

    启动 1. 在桌面新建一个jenkins.bat文件.内容如下: cd /d %JENKINS_HOME% java -jar %JENKINS_HOME%\jenkins.war --httpPor ...

  4. ServletConfig

    ServletConfig Servlet配置 比如web程序中的某一个Servlet需要配置一些初始化信息,需要在web.xml中进行配置 <servlet> <servlet-n ...

  5. Hibernate命名空间怎样实现?

    什么是命名查询?  Hibernate同意在映射文件里定义字符串形式的查询语句.这样的查询方式成为命名查询  使用命名查询有什么优点?  因为使用Hibernate的HQL经常须要在Java代码中写字 ...

  6. 从零单排c++ primer(17)

    (1)假设一个名字在派生类的作用域内无法正确解析,则编译器将继续在外层的基类作用域中寻找该名字的定义. (2)派生类的成员将隐藏同名的基类成员. (3)除了覆盖继承而来的虚函数之外,派生类最好不要重用 ...

  7. Python下载漫画

    上午起来提不起劲,于是就用电脑看漫画,但是在线看漫画好烦,就想下下来看.一个一个点太麻烦,于是花了点时间用python写了个demo,把爱漫画的漫画下载下来,这样就可以随时随地看了.这也是我首次尝试用 ...

  8. 解决Windows8前面板耳机无声的问题

    Windows8已经到来不久了,相信很多朋友已经在使用,在使用时也许会遇到前面板耳机无声的问题,网上的其他办法很麻烦还不一定能解决,在这里我会给大家提供最简单的办法解决这个问题. 百度经验:jingy ...

  9. My.Ioc 代码示例——注册项的注销和更新

    当您需要从 Ioc 容器中注销/删除一个注册项的时候,您会怎么做呢? 有人曾经在 stackoverflow 上提问“如何从 Unity 中注销一个注册项”.对于这个问题,有人的回答是“有趣.你为什么 ...

  10. Linux 网络配置(固定IP)

    通常linux作为服务器系统时,是不推荐安装图形界面的,因此我们需要掌握非图形界面下如何配置网络,主要两种方式,如下: 一.使用SETUP工具(redhat系列才可以,推荐此修改方式) 1.在命令行直 ...