Flask-SocketIO 服务器使用轮询而不是 websockets

Posted

技术标签:

【中文标题】Flask-SocketIO 服务器使用轮询而不是 websockets【英文标题】:Flask-SocketIO server using polling instead of websockets 【发布时间】:2016-05-24 21:11:01 【问题描述】:

我正在开发一个运行良好的 Flask-SocketIO 服务器。

但是,我在服务器日志中收到很多这样的请求:

"GET /socket.io/?EIO=3&transport=polling&t=LBS1TQt HTTP/1.1"

这是我正在使用的代码:

from flask import Flask, render_template, redirect, url_for
from flask_socketio import SocketIO, emit
import json

def load_config():
    # configuration
    return json.load(open('/etc/geekdj/config.json'))

config = load_config()

geekdj = Flask(__name__)

geekdj.config["DEBUG"] = config["debug"]
geekdj.config["SECRET_KEY"] = config["secret_key"]
geekdj.config.from_envvar("FLASKR_SETTINGS", silent=True)

socketio = SocketIO(geekdj)

@geekdj.route('/')
def index():
    return render_template('index.html')

# SocketIO functions

@socketio.on('connect')
def chat_connect():
    print ('connected')

@socketio.on('disconnect')
def chat_disconnect():
    print ("Client disconnected")

@socketio.on('broadcast')
def chat_broadcast(message):
    print ("test")
    emit("chat", 'data': message['data'])

if __name__ == "__main__":
    socketio.run(geekdj, port=8000)

还有index.html中的JS:

<script src="//cdn.socket.io/socket.io-1.4.5.js"></script>
<script type="text/javascript" charset="utf-8">
    $(document).ready(function()

        // the socket.io documentation recommends sending an explicit package upon connection
        // this is specially important when using the global namespace
        var socket = io.connect('http://localhost:8000');

        socket.on('connection', function(socket) 
            socket.emit('foo', foo: "bar");
            socket.join("test");
        );

        socket.on('joined', function(data) 
            console.log('Joined room!');
            console.log(data["room"]);
        );
     );

如果可能的话,我更愿意使用实际的 Websocket,有谁知道为什么 SocketIO 会退回到轮询?

【问题讨论】:

【参考方案1】:

第一个答案有效吗?如果是这样,你应该接受它。如果没有,请发布您的 requirements.txt。

我遇到了同样的问题,通过完全吸收文档页面找到了解决方案:

可以选择这个包依赖的异步服务 三种选择:

eventlet 是性能最佳的选项,支持长轮询和 WebSocket 传输。 gevent 在许多不同的配置中得到支持。 gevent 包完全支持长轮询传输, 但与 eventlet 不同的是,gevent 没有原生 WebSocket 支持。 要添加对 WebSocket 的支持,目前有两种选择。 安装 gevent-websocket 包将 WebSocket 支持添加到 gevent 或一个可以使用 uWSGI 网络服务器,它带有 WebSocket 功能。使用gevent也是一种性能 选项,但略低于 eventlet。 也可以使用基于 Werkzeug 的 Flask 开发服务器,但需要注意的是它缺乏其他两个服务器的性能 选项,所以它应该只用于简化开发 工作流程。此选项仅支持长轮询传输。

基本上,我的虚拟环境中没有 evenlet 和 gevent-websocket。我安装了 eventlet,并且传输升级到 websocket 几乎是瞬时的!希望这会有所帮助。

【讨论】:

您究竟是如何使用 eventlet 来让 socketio 正常工作的?你调用了eventlet.monkey_patch() 还是? 我所做的只是安装它,升级是自动的。 @jacob 关于“此选项仅支持长轮询传输”的问题。使用“socketio = SocketIO(app, async_mode=async_mode)”设置 async_mode 是否允许运行 websocket?还是flask-socketIO应用程序运行在 根据文档,有效的异步模式是“threading、eventlet、gevent 和 gevent_uwsgi”。我的理解是绕过长轮询的唯一方法是不使用内置的 Flask 开发服务器。【参考方案2】:

我找到了解决方案in this other Q/A。

事实证明,SocketIO 使用最近有效的连接类型设置了一个 cookie。就我而言,它是轮询。

所以,我将 JS 中的 SocketIO 连接语句从

var socket = io.connect('http://localhost:8000');

var socket = io.connect(null, port: 8000, rememberTransport: false);

现在在 Chrome 开发者工具的网络选项卡下的 websockets 类型中有活动(以前没有):

【讨论】:

以上是关于Flask-SocketIO 服务器使用轮询而不是 websockets的主要内容,如果未能解决你的问题,请参考以下文章

Socket-IO 使用轮询而不是 Websocket

socket.io 啥时候使用轮询而不是 websockets?

为啥我要使用 RxJS 的 interval() 或 timer() 轮询而不是 window.setInterval()?

Ajax 轮询与 SSE(服务器端的性能)

[翻译] flask-SocketIO

PHP + jQuery - 使用数据库数据进行长轮询不起作用(它不会打破循环)