• NGINX源码之:listen和server_name命令与listening监听创建


    在http块的server块解析中,通过解析listen和server_name命令配置,完成端口监听的初始化,虚拟主机配置关联,实现从host+port到虚拟主机的映射关系。在进入解析源码之前,先来看看server块集中配置:

    server {
            listen       8081 default;//default作为默认虚拟主机配置,当不匹配其他servername时,默认使用该配映射;*:8081与8081等效
            server_name  localhost;
                root   html;
                index  index.html index.htm;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    
    
        server{
            listen localhost:8081;//localhost会被解析出两个ip,一个是ipv4:127.0.0.1;一个是ipv6 [::1]
            server_name www.a.com www.b.com *.c.com;
            location / {
                root   html;
                index  index.html index.htm;
            }
        }
        server{
            listen localhost:8081;//有两个相同的listen配置时,才会构建servername的hash表
            server_name www.test.com  *.t.com;
            location /test {
                root   html;
                index  index.html index.htm;
            }
        }
    
        server{
            listen 127.0.0.1:8082;
            server_name www.a.com .c.com ~^www\.d\..*$;//设置正则格式的servername
            location / {
                root   html;
                index  index.html index.htm;
            }
        }
        server{
            listen 127.0.0.1:8083 default_server;//default_server等同于default
            server_name www.a.com .c.com *.test.com;
            location / {
                root   html;
                index  index.html index.htm;
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    一、listen命令解析
    在解析server块时,首先解析listen命令,这时进入ngx_http_core_listen()方法:
    在这里插入图片描述
    下面主要看下的ngx_parse_url()与ngx_http_add_listen()两个方法
    1、ngx_parse_url()
    在这里插入图片描述
    这里重点关注ipv4的处理:ngx_parse_inet_url();

    在这里插入图片描述
    ngx_inet_resolve_host() 将配置的hostname通过操作系统hosts文件解析出对应的一个或多个ip,再分别每个ip调用ngx_inet_add_addr()
    在这里插入图片描述
    经过上面的URL解析,大概有两种结构,一种是单个ip的,一种是经过host解析出多个ip的:
    单个ip配置的,如listen 8081

    在这里插入图片描述
    多个ip配置的,如listen localhost:8081:
    在这里插入图片描述

    2、ngx_http_add_listen()
    在这里插入图片描述
    ngx_http_add_listen方法完成的结构如下:
    在这里插入图片描述
    最终,在整个listen配置解析阶段,生成的结构如下:

    在这里插入图片描述

    在ports数组中,每个端口可能有两种port元素(ipv4的port元素,ipv6的port元素),每个port元素可能有多个addr,如8081,加入同时配置多个server块,每个server的listen配置分别为 8081、localhost:8081,ports会有两个8081的port元素,那么ipv4port元素中的addrs元素就有两个,分别为0.0.0.0:8081、127.0.0.1:8081;ipv6port元素的addrs数组中元素只有一个[::]:8081;
    当有多个server块,同时配了相同的listen,如多个server块配置listen localhost:8081,那么127.0.0.1:8081、[::]:8081对应的ngx_http_conf_addr元素中的servers数组就会有多个元素。

    在给sockaddr赋值sin_port时,需要将端口号转成网络字节序,网络字节序用的都是大端字节序。内存读取都是按字节读取,每次读取8位,将8081转换字节序:
    8081二进制为:0001 1111 1001 0001;为小端字节序,即每8位从左往右高位到地位,而大端字节序,每8位从左往右是低位到高位;那么转换后为1001 0001 0001 1111,十进制为37141

    二、server_name命令解析

    在这里插入图片描述

    server_name解析完成每个server_name配置关联对应的srv_conf,后续将对server_name优化构建hash表,可通过hash表查找每个server_name对应的srv_conf配置。

    三、ngx_http_optimize_servers()虚拟主机优化
    在这里插入图片描述
    1、ngx_http_server_names()
    方法将单个addr的多个server块配置中server_names配置建立server_name到server块配置srv_conf的映射,然后将多个server块所有的server_name的映射构建hash表。具体构建hash表的方法,参考我的另一篇博客ngx_hash,addr的hash指针指向构建的hash表。
    仅以本例,构造的结构如下:
    在这里插入图片描述

    2、ngx_http_init_listening()
    在这里插入图片描述
    2.1、ngx_http_add_listening()
    在这里插入图片描述
    2.2、ngx_http_add_addrs()
    在这里插入图片描述在这里插入图片描述
    创建listening后的结构如图:
    在这里插入图片描述在整个过程中,会有ngx_addr_t(addr)、ngx_http_conf_addr_t(addr)、ngx_http_in_addr_t(addr)三种类型的addr、分别在listen命令解析(ngx_parse_url)、添加port到ports数组、创建listening三个流程节点中使用。后一个addr通常需要前一个addr复制,需注意区分。

  • 相关阅读:
    全网最全面的SSM整合(没有之一)
    Android 底部导航栏(三、ViewPager+TabLayout+Fragment)简单易懂
    Python爬虫之Splash详解
    2.springboot代理调用
    00_socket_demo
    LeetCode刷题笔记【31】:动态规划专题-3(整数拆分、不同的二叉搜索树)
    嵌入式Linux应用开发-第十二章设备树的改造
    NLP标注工具Brat的简单使用
    ansible学习笔记【12】parted模块
    PHP require、include、require_once 和 include_once 的区别
  • 原文地址:https://blog.csdn.net/qq_22351805/article/details/126079797