美文网首页
flask-sockets小demo在nginx+gunicor

flask-sockets小demo在nginx+gunicor

作者: 晓函 | 来源:发表于2021-04-16 20:14 被阅读0次

小demo:客户端页面发送消息,服务端接受到原文回复过去。

init.py

app = None
def create_app(config_name):
    global app
    app = Flask(__name__)
    #启动websocket server
    from . import socket_server
    socket_server.run()
    ....省略中间代码
    return app

socket_server.py

import json
from flask_sockets import Sockets
from app import app#从app根目录引用app=Flask(__name__)的实例

sockets = Sockets(app)
client_pool = []

@sockets.route('/socket.io/echo')
def echo_socket(ws):
    print('connent...')

    client_pool.append(ws)
    while not ws.closed:
        msg = ws.receive()
        print(f'recevice:{msg}')
        if msg is None:#一般是客户端关闭了
            print('msg is None')
            break
        msg = json.loads(msg)
        ws.send(f'reply : {msg["data"]}')

    client_pool.remove(ws)


def thread_forever(name):
    #pip install flask_sockets
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler

    try:
        #任意未使用端口
        server = pywsgi.WSGIServer(('0.0.0.0', 9000), app, handler_class=WebSocketHandler)
        print(app)
        print('web server start ... ')
        server.serve_forever()#这个会一直阻塞
        print('serve_forever end ... ')
    except Exception as e:
        print(f'server err: {e}')
        return None

def run():
    # 为了防止create_app调用run这里被serve_forever阻塞,导致gunicorn超时杀掉进程
    _thread.start_new(thread_forever, ('server',))

socket_client.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>websocket demo</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js"></script>
</head>
<body>
    <div id="content" style="width: 300px;height: 300px;border:1px solid #000;padding:6px;font-size: 12px;">
        
    </div>
    <br>
    <input id="say" type="input" name="say">
    <button onclick="sendtext()">发送</button>

    <script>
            //var ws = new WebSocket("ws://mp-api.hmyy.com:9000/socket.io/echo");  //本地测试,连接本地server
            var ws = new WebSocket("wss://mp-api.hmuu.com/socket.io/echo");  //生产环境,连接服务器server-ssl
            ws.onopen = function(event){
                $("#content").append("web socket 已连接<br>");
               console.log('web socket 已连接');
                ws.send( JSON.stringify({'type':'open', 'data':{'name':'Jerry'}}));
            };

            ws.onmessage = function (event) {
                $("#content").append(event.data+"<br>");

            };
            ws.onclose = function(){
                $("#content").append("连接已关闭...<br>");
            }

            function sendtext(){
                var txt = $('#say').val();
                $('#say').val('');
                console.log(txt);
                ws.send( JSON.stringify({'type':'say', 'data':''+txt}));
            }

    </script>
    </body>
</html>

遇到的坑

坑1 - nginx

以上代码在本地runserver是没问题的。
但是放到生成环境nginx+gunicorn就不行了。
我们网站访问一般是80和443,所以nginx也就是监听这两个端口,然后转发给flask的web服务端口,如8000。
并且服务器也不会放行其他端口到外网,所以我们客户端需要socket连接服务器到80/443端口,nginx接受到后,就转发给flask的socket监听端口,如9000.我们就还需要设置nginx配置,转发。
nginx中加上配置

        location ^~/socket.io {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_read_timeout 300s;
            proxy_pass http://127.0.0.1:9000;
        }

所以我们的url路径ws://mp-api.hmyy.com:9000/socket.io/echo中会有socket-io字符串,只是为了nginx识别规则转发。(以上代码已经加上socket-io)

坑2 - gunicorn

gunicorn还会运行30秒就提示[CRITICAL] WORKER TIMEOUT,然后自动重启进程。


image.png

因为我们init.py在create_app()中执行的socket_server.run(),server.serve_forever()是一直阻塞的,所以create_app一直没有return,gunicorn就一直挂起了。
解决:我们应该使用thread执行run()里面的代码
以上代码我已经改成线程模式了。

坑3 - cdn

在本地测试环境,连接能一直保持存在。在生成环境10秒就断开,nginx的 proxy_read_timeout 600s;设置了10分钟,还是10秒断开。后来发现是腾讯cdn的问题,由于api域名使用了腾讯cdn,cdn主要由于缓存,websocket是动态内容,10秒没交互就会超时被断开,所以我们单独开了一个ws.xxx.com的子域名,用于ws连接,这样就没问题了。


image.png

取消cdn后,就是按照nginx设置都5分钟超时自动关闭了


image.png

相关文章

网友评论

      本文标题:flask-sockets小demo在nginx+gunicor

      本文链接:https://www.haomeiwen.com/subject/mtqylltx.html