socketio如何过滤事件(特别是flask-socketio)

How does socketio filter events (specifically flask-socketio)

背景

假设有 N 个客户端和 N 个节点,每个节点都会发出一条消息,其中包含统计信息和它的名称。单个客户端 n ∈ N 只关心特定节点 n ∈ N.

建议的解决方案

当服务器收到来自节点的消息时,每个客户端都会监听一个特定的事件 node_namenode_name, 发出一个事件 node_name

问题

事件发出时node_name,

是否会将消息发送给每个客户端 n ∈ N,然后在没有针对特定 node_name

的侦听器时被丢弃

服务器是否保留元数据并知道哪些 clients/connections 正在侦听事件 node_name 并且只发送给特定的客户端 n

修改

后者能否通过命名空间实现

是否建议为每个节点创建一个房间?这些房间会充当元数据

事件在客户端级别过滤,而命名空间和房间在服务器级别

同一命名空间和房间内的所有已连接客户端都会收到所有事件

查看源代码,我们发现 flask_socketio 在 socketio 之上提供了一个层,其中包含一些包装函数 __init__.py 从其核心文件的实例化属性调用函数。

base_manager.py 中的 emit 函数本身就是

    def emit(self, event, data, namespace, room=None, skip_sid=None,
         callback=None, **kwargs):
    """Emit a message to a single client, a room, or all the clients
    connected to the namespace."""
    if namespace not in self.rooms or room not in self.rooms[namespace]:
        return
    for sid in self.get_participants(namespace, room):
        if sid != skip_sid:
            if callback is not None:
                id = self._generate_ack_id(sid, namespace, callback)
            else:
                id = None
            self.server._emit_internal(sid, event, data, namespace, id)

它使用了一个名为 get_participants 的函数,看起来像这样

def get_participants(self, namespace, room):
    """Return an iterable with the active participants in a room."""
    for sid, active in six.iteritems(self.rooms[namespace][room].copy()):
        yield sid

最后看一下函数 enter_room 揭示了存储客户端层次结构的对象的结构

def enter_room(self, sid, namespace, room):
    """Add a client to a room."""
    if namespace not in self.rooms:
        self.rooms[namespace] = {}
    if room not in self.rooms[namespace]:
        self.rooms[namespace][room] = {}
    self.rooms[namespace][room][sid] = True

鉴于结构,最好使用node_name作为特定预定义命名空间下的房间名称。