与网络有关的配置命令主要有两个:listen和sever_name。首先先了解这两个命令的用法。

listen命令设置nginx监听地址,nginx从这里接受请求。对于IP协议,这个地址就是address和port;对于UNIX域套接字协议,这个地址就是path。 一条listen指令只能指定一个address或者port。 address也可以是主机名。 比如:

1 listen 127.0.0.1:8000;
2 listen 127.0.0.1;
3 listen 8000;
4 listen *:8000;
5 listen localhost:8000;

UNIX域套接字则使用“unix:”前缀:

可以为listen指令定义若干额外的参数,这些参数用于套接字相关的系统调用。 这些参数可以在任何listen指令中指定,但是对于每个address:port,只能定义一次。具体参数看以到nginx帮助文档中查到,这里就不再说明了。

listen指令描述虚拟主机接受连接的地址和端口,用server_name指令列出虚拟主机的所有主机名。

第一个名字成为虚拟主机的首要主机名。

1 server { 2 server_name example.com *.example.com www.example.*; 3 }

更详细的介绍:http://nginx.org/cn/docs/http/server_names.html

ngx_http_add_listen中调用了ngx_http_add_addresses和ngx_http_add_address函数,先看下ngx_http_add_addresses:

这个函数代码很简单,初始化地址列表,并调用ngx_http_add_server将新的虚拟主机的配置加入到address:port对应的虚拟主机列表中。下面再看下ngx_http_add_server函数:
 1 static ngx_int_t
 2 ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
 3     ngx_http_conf_addr_t *addr)
 4 {
 5     ...
 6     server = ngx_array_push(&addr->servers);  //添加新的虚拟主机配置
 7     if (server == NULL) {
 8         return NGX_ERROR;
 9     }
10     *server = cscf;
11     return NGX_OK;
12 }

这个函数主要是把server_name命令后面各个主机名放到当前虚拟主机配置的server_names数组中。

上面代码主要就是将每个address:port对应的所有域名与域名所在的虚拟主机配置信息建立hash映射,这样就可以通过域名快速找到域名所在的虚拟主机配置信息。有关nginx的hash可以参考 nginx源码分析之hash的实现 这篇文章。下面再看下ngx_http_init_listening函数:

 1 static ngx_int_t
 2 ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
 3 {
 4     ...
 5     addr = port->addrs.elts;
 6     last = port->addrs.nelts;
 7     if (addr[last - 1].opt.wildcard) {
 8         addr[last - 1].opt.bind = 1;
 9         bind_wildcard = 1;
10 
11     } else {
12         bind_wildcard = 0;
13     }
14     i = 0;
15     while (i < last) {  //last代表的是address:port的个数
16         //忽略隐式绑定
17         if (bind_wildcard && !addr[i].opt.bind) {
18             i++;
19             continue;
20         }
21         //这个函数里面将会创建,并且初始化listen结构,这个listen已经存放在cycle结构的listen数组中
22         ls = ngx_http_add_listening(cf, &addr[i]);
23         if (ls == NULL) {
24             return NGX_ERROR;
25         }
26         hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
27         ...
28         ls->servers = hport;
29         if (i == last - 1) {  //将*:port和没有显式bind的address:port放在同一个listen中
30             hport->naddrs = last;
31         } else {
32             hport->naddrs = 1;
33             i = 0;  //i重新赋值为0
34         }
35         switch (ls->sockaddr->sa_family) {
36         ...
37         default: /* AF_INET */
38             if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {  //初始化虚拟主机相关的地址,设置hash等等.
39                 return NGX_ERROR;
40             }
41             break;
42         }
43         addr++;
44         last--;
45     }
46     return NGX_OK;
47 }

建立监听套接字是在ngx_open_listening_sockets中完成,这个函数是在ngx_init_cycle中被调用的。