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的流程如下。其中需要经过两次数据结构的转换。
server {
listen *:2121;
proxy_timeout 65534;
proxy_pass ftp1;
alg ftp;
}
server {
listen 10.250.64.103:2121;
proxy_timeout 65534;
proxy_pass ftp;
alg ftp;
}
server {
listen 60.60.60.77:2121;
proxy_timeout 65534;
proxy_pass ftp;
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 ftp;
alg ftp;
}
server {
listen 60.60.60.77:2121;
proxy_timeout 65534;
proxy_pass ftp;
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 ftp;
alg ftp;
}
server {
listen 60.60.60.77:2121;
proxy_timeout 65534;
proxy_pass ftp;
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 ftp;
alg ftp;
}
server {
listen 10.250.64.103:2121-2123;
proxy_timeout 65534;
proxy_pass ftp;
alg ftp;
}
server {
listen 60.60.60.77:2121;
proxy_timeout 65534;
proxy_pass ftp;
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。
函数的大体流程是:
当连接初次建立时,(对于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做了很多额外的工作进行了数据结构的两次转化。但是也没有想到更好的办法可以省略这两次转换。
另外,这篇文章更多是帮助自己理解代码而写的,希望对大家也有帮助。