Flask-SocketIO服务器使用轮询而非WebSockets

6

我正在开发一个 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"]);
        });
     });

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

2个回答

10

第一个答案有效吗?如果有效,您应该接受它。否则,请发表您的 requirements.txt。

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

该软件包依赖的异步服务可以从以下三个选择中选择:

  • eventlet 是最佳性能选项,支持长轮询和 WebSocket 传输。
  • gevent 在许多不同的配置中受支持。使用 gevent 软件包完全支持长轮询传输,
    但与 eventlet 不同,gevent 没有本机 WebSocket 支持。
    要添加对 WebSocket 的支持,当前有两个选项:
    安装 gevent-websocket 软件包可向 gevent 添加 WebSocket 支持,
    或者可以使用带有 WebSocket 功能的 uWSGI web 服务器。
    使用 gevent 也是一个性能良好的选项,但略低于 eventlet。
  • 基于 Werkzeug 的 Flask 开发服务器也可以使用,但要注意它缺乏其他两个选项的性能,
    因此只应用于简化开发工作流程。此选项仅支持长轮询传输。

实际上,我的虚拟环境中没有 evenlet 或 gevent-websocket,我安装了 eventlet,
并且将传输升级到 WebSocket 几乎是瞬间完成的!希望这能帮到您。


2
你是如何确切地使用 eventlet 以使 socketio 正常工作的?你调用了 eventlet.monkey_patch() 还是其他什么方法? - Milan Velebit
我所做的只是安装它,升级是自动的。 - jacob
@jacob 关于“This option only supports the long-polling transport.”的问题。使用“socketio = SocketIO(app,async_mode = async_mode)”设置async_mode是否允许运行Websockets?还是flask-socketIO应用程序在运行中? - carl crott
根据文档,有效的异步模式为“线程、eventlet、gevent和gevent_uwsgi”。我理解的是,摆脱长轮询的唯一方法是不使用内置的Flask开发服务器。 - jacob

7
我在这个问题解答中找到了解决方案。
原来,SocketIO会设置一个包含最近可用的连接类型的cookie。在我的情况下,它是轮询方式。
所以,我将JS中的SocketIO连接语句从 var socket = io.connect('http://localhost:8000'); 改成了 var socket = io.connect(null, {port: 8000, rememberTransport: false}); 现在,在Chrome开发者工具的网络选项卡下出现了websocket类型的活动(以前没有): enter image description here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接