flask-socketio可以实现全双工通信,本文使用的版本是:

python==2.7

Flask-SocketIO==4.3.2

gevent-websocket==0.10.1

下面直接看服务端的代码:

其中前端直接访问也要访问这个name_space

# coding: utf-8
import json

from flask import Flask, request
from flask_socketio import SocketIO, emit

from monitor_system import SystemInfoMonitor

name_space = '/websocket'  # 名称空间,写对才能通信
app = Flask(__name__, template_folder="template")
app.secret_key = 'tong-yi-tai-wan'
socketio = SocketIO(app, cors_allowed_origins='*')  # 允许跨域
client_query = []  # 这里也可以用自带的join_room之类的方法


@socketio.on('connect', namespace=name_space)  # 有客户端连接会触发该函数
def on_connect():
    # 建立连接 sid:连接对象ID
    client_id = request.sid
    client_query.append(client_id)
    # emit(event_name, broadcasted_data, broadcast=False, namespace=name_space, room=client_id)  #指定一个客户端发送消息
    # emit(event_name, broadcasted_data, broadcast=True, namespace=name_space)  #对name_space下的所有客户端发送消息
    print(u'new connection,id=[%s] connected, now have [%s] connections' % (client_id, len(client_query)))


@socketio.on('disconnect', namespace=name_space)  # 有客户端断开WebSocket会触发该函数
def on_disconnect():
    # 连接对象关闭 删除对象ID
    client_query.remove(request.sid)
    print(u'connection id=[%s] exited, now have [%s] connections' % (request.sid, len(client_query)))


# on('消息订阅对象', '命名空间区分')
@socketio.on('message', namespace=name_space)
def on_message(message):
    """ 服务端接收消息 """
    print(u'从id=%s客户端中收到消息,内容如下:' % request.sid)
    print(message)
    #指定一个客户端发送消息
    # emit('my_response_message', "我收到了你的信息", broadcast=False, namespace=name_space, room= request.sid)
    # 对name_space下的所有客户端发送消息
    emit('my_response_message', u"我收到了你的信息", broadcast=True, namespace=name_space)  


@app.route('/sender')
def get_monitor_system_info():
    data = SystemInfoMonitor().run()
    for client in client_query:
        # client.send(json.dumps(data))
        # emit('monitor', json.dumps(data),  broadcast=True, namespace=name_space)
        # 前端要监听这个my_response_message
        emit('my_response_message', json.dumps(data), broadcast=False, namespace=name_space, room=client)
    return "ok"



if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=9999, debug=True)

后台可以写一个sender方法,然后通过apscheduler模块,启动一个定时任务,每隔几秒就调用一次sender方法,将数据推送给前端,这样也不会有阻塞。前端只需要处理好监听就可以跟我通信获取到数据。但是这样就会后台持续刷新接口

看下官方文档,正确的做法应该如下:

# coding: utf-8
import json
from threading import Lock

import psutil
from flask import Flask, request
from flask_socketio import SocketIO, emit

from app.config import conf
from app.syscfg.models import SystemMessage
from worker import rclient

name_space = '/websocket'
app = Flask(__name__, template_folder="template")
app.secret_key = 'tong-yi-tai-wan'
socketio = SocketIO(app, cors_allowed_origins='*')
client_query = []

thread = None
thread_lock = Lock()

SYSTEM_INFO = json.dumps({})
POWER_INFO = {
    'percent': 100, 'power_plugged': True, 'remain_time': 'unlimited'
}



def get_count_for_sysmsg():
    from app import create_app
    with create_app().app_context():
        sysmsg_count = SystemMessage.query.filter(SystemMessage.read == 0).count()
        return sysmsg_count


def background_thread():
    """Example of how to send server generated events to clients."""
    while True:
        # 监控
        monitor_data = get_system_info()
        socketio.emit('my_response_message', monitor_data, namespace=name_space)
        # 电池
        resp = get_power_info()
        socketio.emit('power', json.dumps(resp), namespace=name_space)
        # 站内信数量
        count = get_count_for_sysmsg()
        socketio.emit('message', json.dumps({'count': count}), namespace=name_space)

        socketio.sleep(3)


@socketio.on('connect', namespace=name_space)  # 有客户端连接会触发该函数
def on_connect():
    global thread
    with thread_lock:
        if thread is None:
            thread = socketio.start_background_task(background_thread)

    emit('my_response_message', SYSTEM_INFO)
    emit('power', json.dumps(POWER_INFO))


@socketio.on('disconnect', namespace=name_space)  # 有客户端断开WebSocket会触发该函数
def on_disconnect():
    # 连接对象关闭 删除对象ID
    # client_query.remove(request.sid)
    print(u'connection id=[%s] exited, now have [%s] connections' % (request.sid, len(client_query)))


# on('消息订阅对象', '命名空间区分')
@socketio.on('message', namespace=name_space)
def on_message(message):
    """ 服务端接收消息 """
    print(u'从id=%s客户端中收到消息,内容如下:' % request.sid)
    print(message)
    # emit('my_response_message', "我收到了你的信息", broadcast=False, namespace=name_space, room= request.sid)  #指定一个客户端发送消息
    emit('my_response_message', u"我收到了你的信息", broadcast=True, namespace=name_space)  # 对name_space下的所有客户端发送消息

我后来部署需要nginx做代理,nginx的主要配置如下:

location /socket.io {
            proxy_http_version 1.1;
            proxy_buffering off;
            proxy_read_timeout 300s;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_pass http://127.0.0.1:9999/socket.io;
        }

前端部分获取后台如下(访问82,监听转发到9999端口):

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐