带有广播 = true 的 Flask SocketIO Emit 不会向发送者发送消息

Posted

技术标签:

【中文标题】带有广播 = true 的 Flask SocketIO Emit 不会向发送者发送消息【英文标题】:Flask SocketIO Emit with broadcast=true does not send message to sender 【发布时间】:2020-04-22 01:23:50 【问题描述】:

第一次在这里发布海报。我正在尝试使用 Flask-SocketIO 组合一个聊天室应用程序,并且很难让一个微小但至关重要的部分工作。当我在服务器中调用 emit 方法并设置 broadcast=True 标志时,预期的行为是它会在客户端为所有用户(包括发送者)触发相应的 socket.on 事件。但是,我的代码显然只对发件人以外的所有客户端执行此操作。这与https://flask-socketio.readthedocs.io/en/latest/ 的文档相反,其中指出:

在启用广播选项的情况下发送消息时,连接到命名空间的所有客户端都会收到它,包括发送者。当不使用命名空间时,连接到全局命名空间的客户端会收到消息。

我需要它来发送消息并为发送者以及所有其他客户端触发 socket.on 事件。谁能解释我在这里做错了什么?因为这似乎是一个基本功能,我一定错过了一些非常明显的东西。

服务器代码:

import os
import requests

from flask import Flask, jsonify, render_template, request
from flask_socketio import SocketIO, emit, join_room, leave_room

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
socketio = SocketIO(app)

channels = ['a', 'b', 'c', 'testing', 'abc', '123']
ch_msgs = 'a': ['testing', '1234', 'high five'], 'b': ['hello']
msg_limit = 100

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

@socketio.on('add channel')
def add(data):
    new_channel = data
    channels.append(new_channel)
    ch_msgs[new_channel] = list()

    emit('announce channel', new_channel, broadcast=True)

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

javascript

document.addEventListener('DOMContentLoaded', () => 

    var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);

    socket.on('connect', () => 

        document.querySelector('#add_channel').onclick = () => 

            const new_channel = document.querySelector('#new_channel').value;

            socket.emit('add channel', new_channel);

        ;


    );

    socket.on('announce channel', data => 

        const li = document.createElement('li');

        li.innerHTML = '#' + `$data`;

        $('#channel_list').append(li);

    );
);

HTML/CSS sn-p:

<h3>Chat Channels</h3>
<br>

<ul id='channel_list' style='list-style-type:none;'>
</ul>

<form class='channel'>
     <input type='text' id='new_channel' placeholder='add new channel'><input type='submit' id='add_channel' value='Add'>
</form>

【问题讨论】:

【参考方案1】:

实际上所有客户端都在接收发送的消息,包括发送者,但这里的问题是发送者的页面在表单提交后立即刷新,(这是表单的默认行为)从而导致丢失所有本地数据。

为了防止这种情况,您需要使用event.preventDefault() 方法。在您的情况下,您可以像这样更改 connect 事件的事件处理程序:

socket.on('connect', () => 
    document.querySelector('#add_channel').onclick = event => 
        event.preventDefault();
        const textinput = document.querySelector('#new_channel')
        const new_channel = textinput.value;
        textinput.value = "";    // Clear input after value is saved
        socket.emit('add channel', new_channel);
    ;
);

【讨论】:

非常感谢!我从不怀疑这是问题所在。出于好奇,如果我使用类似 onsubmit 而不是 onclick 会发生同样的行为吗? (我只是尝试用 .onsubmit 替换 .onclick 但它实际上并没有做任何事情) @FarmageddonNow onsubmit 事件将应用于form 元素(而不是button),因此如果您决定使用onsubmit,请选择相应的form 元素#add_channel 按钮。是的,同样的默认行为适用于onsubmit

以上是关于带有广播 = true 的 Flask SocketIO Emit 不会向发送者发送消息的主要内容,如果未能解决你的问题,请参考以下文章

使用 Flask-SQLAlchemy 事件 API 广播到 Flask-SocketIO?

广播机制的CS模型实现

如何使用 websockets 通过 Flask 向特定用户发送消息?

socket.io:关于广播和最大连接的查询

如何使用 ssl 启动 flask_socketio 应用程序?

带有广播连接的 Spark 流式传输