Nginx 模块在定义服务时,一般是通过配置server里面的listen端口来完成。根据不同的listen语法,可以实现下了几种功能。

1. 最简单的,可以通过不同ip和port,对应某一个服务。

server1 {

listen 1.2.3.4:2121;

上面的配置,可以让所有到1.2.3.4端口是2121的连接进行server1规定的服务。

2. 通过指定port 范围,实现多个port对应一个服务。

server2 {

listen 1.2.3.4:2121-2123;

上面的配置就可以实现所有到ip地址1.2.3.4端口从2121到2123的连接都指向同样的服务server2。

3. 如果Nginx所在的服务器有多个ip 地址,可以通过不同的ip和相同的port组合实现不同的服务。

server3 {

listen 1.2.3.4:2121;

server4{

listen 2.3.4.5:2121;

当客户端连接 1.2.3.4:2121 时,提供server3的服务。连接2.3.4.5:2121时,提供server4的服务。

4. 如果Nginx所在的服务器有多个ip 地址,通过配置监听所有ip地址上相同的某些port。

server5 {

listen 2121;

server6{

listen *:2121;

上述两种配置的功能是一样的,通过省略ip地址或者用*表示ip地址,可以达到只要连接到达任何一个ip地址的端口2121都可以进行server5或者server6的目的。

5. 如果Nginx所在的服务器有多个ip 地址,可以通过如下配置,针对同一个port,让特定ip的连接进行某个服务,剩余ip的连接进             行另外的服务。

server7 {

listen *:2121;

server8{

listen 1.2.3.4:2121;

连接到1.2.3.4:2121的连接进行server8的服务。连接别的ip地址的2121port进行server7的服务。

二 实现原理

在进行代码分析之前,让我们先来看看与stream模块的listening port相关的数据结构是如何组织的。用户配置的server listen属性,最终需要生成ngx_listen_t结构。

图一  stream 模块监听端口相关数据结构

从配置listen到生成ngx_listen_t的流程如下。其中需要经过两次数据结构的转换。

  1. 在配置解析阶段,server配置的listen port生成的ngx_stream_listen_t结构被存放到下图的右上角的红色线框中。也就是stream模块对应的ngx_stream_core_main_conf_t结构中的listen字段所对应的链表。
  2. 然后把链表ngx_stream_listen_t转换成ngx_stream_conf_port_t结构。通过这个转换可以把所有端口相同的ngx_stream_listen_t合并成一个ngx_stream_conf_port_t结构。并且把这些具有相同端口的ngx_stream_listen_t结构对应的地址存放到生成的那个ngx_stream_conf_port_t结构的地址数组中.
  3. 最后通过ngx_stream_optimize_servers函数,把ngx_stream_conf_port_t结构转化成ngx_listen_t结构。转换的原则是:如果没有通配监听(listen *:2121或者listen 2121),每一对唯一的host address和port生成一个ngx_listen_t。相反,如果有通配监听,所有相同的port (2121)对应的所有的地址,只生成一个ngx_listen_t结构,同时把所有的对应的port的地址存放到ngx_listen_t结构的addrs数组中。

server {

listen *:2121;

proxy_timeout 65534;

proxy_pass vpnftp1;

alg ftp;

server {

listen 10.250.64.103:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

server {

listen 60.60.60.77:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

上述例子会在上述转换过程中,会生成3个ngx_stream_listen_t,1个 ngx_stream_conf_port_t,因为有通配符的存在只会1               个ngx_listen_t.

server {

listen 10.250.64.103:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

server {

listen 60.60.60.77:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

上述例子会在上述转换过程中,会生成2个ngx_stream_listen_t,1个 ngx_stream_conf_port_t,因为没有通配符所以生成2              个ngx_listen_t。

server {

listen 60.60.60.77:2122;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

server {

listen 60.60.60.77:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

上述例子会在上述转换过程中,会生成2个ngx_stream_listen_t,2个 ngx_stream_conf_port_t, 2个ngx_listen_t.

server {

listen *:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

server {

listen 10.250.64.103:2121-2123;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

server {

listen 60.60.60.77:2121;

proxy_timeout 65534;

proxy_pass vpnftp;

alg ftp;

上述例子会在上述转换过程中,会生成5个ngx_stream_listen_t,3个 ngx_stream_conf_port_t, 3个ngx_listen_t.

三 代码流程

在配置解析过程中,对应于stream模块配置解析入口是ngx_stream_block.在此函数中,对于stream server中对应的每一个listen字段,相应的解析函数是ngx_stream_core_listen。

函数的大体流程是:

  1. 调用ngx_parse_url -> ngx_parse_inet_url 生成了ngx_url_t数据结构。在ngx_url_t这个结构中,会存放listen定义的所有的port和可能的地址。如果语法是 listen 2121. 则会生成一个port,和一个INADDR_ANY地址。如果语法是listen *:2121,也会生成一个port,和一个INADDR_ANY地址。如果语法是listen 1.2.3.4:2121,生成一个port,和一个1.2.3.4的地址。如果语法是listen 1.2.3.4:2121-2123 则生成3个port和一个1.2.3.4的地址。如果语法是listen hostname:2121-2123则会生成3个port并且根据对hostname的域名解析得到的地址个数生成相应的地址数量。最后通过ngx_inet_add_addr函数把总数为port_num * addr_num数量的addr存放到ngx_url_t结构中。
  2. 生成上述的结构ngx_url_t后,根据结构中地址的个数 (port_num * addr_num)生成相应数量的ngx_stream_listen_t添加到ngx_stream_core_main_conf_t结构中的listen成员中。同时解析比如reuse,sndbuf,rcvbuf等属性。
  3. 通过函数ngx_stream_add_ports把上述的listen成员中的ngx_stream_listen_t数据按照相同的port number生成一个ngx_stream_conf_port_t的原则把所有的ngx_stream_listen_t结构转换成ngx_stream_conf_port_t结构。对于原来ngx_stream_listen_t中port number相同但是地址不相同的情况把所有的地址都组合起来存放到同一个ngx_stream_conf_port_t结构中的addr数组中。
  4. 通过函数ngx_stream_optimize_servers把上述的ngx_stream_conf_port_t结构定义的port转变成ngx_listening_t结构。转换的规则是:对于有通配匹配的情况(list *:2121或者listen 2121)的端口,如果有几个server对应的port number是一样的,则会生成唯一的一个ngx_listen_t结构,然后把几个server对应的地址存放到ngx_listen_t的地址数组中。对于没有通配匹配的端口,则会根据唯一的地址和端口对生成一个唯一的ngx_listen_t结构。每一个结构中只包含一个addr_t结构。

当连接初次建立时,(对于udp协议路径是ngx_event_recvmsg,对于tcp协议路径是ngx_event_accept),ngx_stream_init_connection函数得到调用。此时如果对应connection上的ngx_listen_t对应的addr有多个。(针对listen *情况),根据连接的Nginx侧的连接信息来确定使用的server是哪一个。通过这个server来连接upstream结构和server的context.

为了支持监听端口的通配匹配,Nginx做了很多额外的工作进行了数据结构的两次转化。但是也没有想到更好的办法可以省略这两次转换。

另外,这篇文章更多是帮助自己理解代码而写的,希望对大家也有帮助。

一 简介Nginx 模块在定义服务时,一般是通过配置server里面的listen端口来完成。根据不同的listen语法,可以实现下了几种功能。 1. 最简单的,可以通过不同ip和port,对应某一个服务。server1 { listen 1.2.3.4:2121;}上面的配置,可以让所有到1.2.3.4端口是2121的连接进行server1规...
Nginx 监听端口 管理      每监听一个TCP端口,都将使用一个独立的ngx_http_conf_port_t结构体表示。ngx_http_conf_port_ttypedef struct { //socket地址家族 ngx_int_t family; // 监听端口 in_port_t port; // 监听端口 下对应
1、安装 nginx ./configure --prefix=/usr/local/ nginx --with-http_stub_status_module --with-http_ssl_module --with- stream --with- stream _ssl_preread_module --with- stream _ssl_module --user= nginx --group= nginx 2、配置 nginx #user nobody; worker_processes 1;#error_log l
worker_processes 1; //主从进程 #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/ nginx .pid; events { worker_connections 1024; http { include mime.types; default_type app
nginx -1.9.0 已发布,该版本增加了 stream 模块 用于一般的TCP 代理和负载均衡,ngx_ stream _core_module 这个 模块 在1.90版本后将被启用。但是并不会默认安装, 需要在编译时通过指定 --with- stream 参数来激活这个 模块 。 1)配置 Nginx 编译文件参数 ./configure --with- stream 2)编译、安装,make && make install make & ma...
通过查看 Nginx 的并发连接,我们可以更清除的知道网站的负载情况。 Nginx 并发查看有两种方法(之所以这么说,是因为笔者只知道两种),一种是通过web界面,一种是通过命令,web查看要比命令查看显示的结果精确一些。下面介绍这两种查看方法; 1.通过浏览器查看   通过web界面查看时 Nginx 需要开启status 模块 ,也就是安装 Nginx 时加上        –with-http...
nginx stream 模块 是用于 处理 TCP和UDP流量的 模块 。它允许你在不破坏原始数据流的情况下,对流量进行路由、载均衡和代理等操作。下是 stream 模块 的一些常见配置指令的详解: 1. ` stream `:定义 stream 模块 的全局配置块。 stream { 2. `up stream `:定义上游服务器列表。可以使用`server`指令指定上游服务器的地址和端口。 up stream backend { server backend1.example.com:12345; server backend2.example.com:12345; 3. `server`:定义 stream 模块 的监听服务器。可以使用`proxy_pass`指令将流量代理到上游服务器。 server { listen 12345; proxy_pass backend; 4. `proxy_pass`:将流量代理到指定的上游服务器。 proxy_pass backend; 5. `resolver`:指定解析器的地址,用于解析上游服务器的域名。 resolver 8.8.8.8; 6. `balancer`:定义负载均衡的算法和参数。 up stream backend { server backend1.example.com:12345 weight=5; server backend2.example.com:12345; balancer least_conn; 7. `ssl_preread`:基于SSL握手前的数据,用于决定将流量路由到哪个上游服务器。