记录日常工作关于系统运维,虚拟化云计算,数据库,网络安全等各方面问题。

环境

  • OS: Centos6-x86_64

  • Nginx: 1.12.1


编译安装Nginx

从1.9.0开始,nginx就支持对TCP的转发,而到了1.9.13时,UDP转发也支持了。提供此功能的模块为ngx_stream_core。不过Nginx默认没有开启此模块,所以需要手动安装。

cd /usr/local/src
wget http://nginx.org/download/nginx-1.12.1.tar.gz
tar zxf nginx-1.12.1.tar.gz
cd nginx-1.12.1
./configure --prefix=/usr/local/nginx --with-stream --without-http
make && make install

Note:由于是传输层转发,本着最小化原则,就关闭了http功能。


配置Nginx

TCP转发

目标:通过3000端口访问本机Mysql(其中mysql使用yum安装,默认配置文件)

/usr/local/nginx/conf/nginx.conf配置如下:


user  nobody;

worker_processes  auto;

#error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {

    use epoll;

    worker_connections  1024;

}


stream {

    server {

        listen 3000;

        proxy_pass 127.0.0.1:3306;


    # 也支持socket

    # proxy_pass unix:/var/lib/mysql/mysql.socket;

    }

}


首先,先通过3306端口访问mysql:




然后,启动Nginx:




最后使用3000端口访问mysql:



UDP转发

目标: 发送UDP数据到3000端口,3001端口可以接收


/usr/local/nginx/conf/nginx.conf配置如下:


user  nobody;

worker_processes  auto;


#error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;


#pid        logs/nginx.pid;


events {

    use epoll;

    worker_connections  1024;

}



stream {

    server {

        listen 3000 udp;

        proxy_pass 127.0.0.1:3001;


    }

}

这里写一个my_socket_server.py侦听在3001端口,用于接收UDP数据:


# coding=utf-8


import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.bind(('127.0.0.1', 3001))

print ('start server on [%s]:%s' % ('127.0.0.1', 3001))

while True:

    data, addr = sock.recvfrom(1024)

    print ('Received from %s:%s' % (addr,data))

    sock.sendto(b'Hello, %s!' % data, addr)


再写一个my_socket_client.py用于向Nginx侦听的3000端口发送数据:


# coding=utf-8


import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:

    data = raw_input('Input msg: ')

    if len(data) == 0:

        continue

    s.sendto(data.encode(), ('127.0.0.1', 3000))

    print (s.recv(1024).decode('utf-8'))

同时运行两个脚本,在client端发送数据:




4.gif

UDP转发遇到的一个坑

修改下client脚本,改为连续发送2000个数据包:

# coding=utf-8


import socket


s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)


for data in range(2000):

    s.sendto(str(data).encode(), ('127.0.0.1', 3000))

    print (s.recv(1024).decode('utf-8'))


然后运行client脚本,发现经常会遇到如下情况:

image.png

由图可知只成功了511个。

查看文档得知listen指令有个backlog参数,此参数在Linux系统中默认为511:

 

悲剧的是backlog参数和udp参数不能同时使用。如果哪位朋友有好的解决办法,请赐教!!!!

“UDP转发遇到的一个坑”部分遇到的问题,client成功的连续发送了511条UDP协议与listen指令的backlog参数在Linux平台的默认值一致只是巧合,其实与listen的backlog参数没有关系,该参数与udp是不兼容的。然后查看error.log会发现,问题是“1024 worker_connections are not enough”,也就是说工作进程中并发连接数达到上限(1024)了。然后问题是为什么nginx给被代理服务器转发UDP协议,会一直占用连接呢?前面引用的链接中给出了解答,是因为我们没有设置“proxy_responses"指令,因此nginx默认是不限制来自被代理服务器的响应数据报数量的。因此,使用py脚本连续给nginx发送UDP协议时,nginx在收到第一个UDP协议时,会与被代理的服务器(python_server脚本)建立连接,然后得到来自被代理服务器的响应数据报,同时也收到了第二个UDP协议,又与被代理服务器建立连接,然后得到了第二个UDP协议对应的响应数据报...由于没有限制”proxy_responses",导致每一次为转发UDP协议而与被代理服务器建立的连接都不认为会话结束,都没有断开,因此很快会话数量就达到了配置的上限(worker_connections)。我们服务器每次会回复一条UDP协议,因此增加一条指令"proxy_responses 1;"就可以了。


作者:胖宝宝王
链接:https://www.jianshu.com/p/244386221cc5
 




转载请标明出处【使用Nginx代理转发TCP/UDP协议】。

《www.micoder.cc》 虚拟化云计算,系统运维,安全技术服务.

网站已经关闭评论