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

Posted

技术标签:

【中文标题】如何使用 websockets 通过 Flask 向特定用户发送消息?【英文标题】:How to use websockets to send message to specific user with Flask? 【发布时间】:2014-12-31 09:45:30 【问题描述】:

在我使用Flask 构建的网站中,人们可以互相发送消息。当用户收到 pm 时,我现在想实现一个类似于 *** 的通知。由于 SO 使用 websockets 实现了这一点,我开始使用 this tutorial 在 websockets 中实现 Flask-socketIO(与 Socket.io 一起使用)。

我按照教程下载了the example,我了解其中的代码。然而,我不明白的是:

    我如何知道登录的人是否打开了网站并连接到 websockets? 如何向该特定用户发送消息?

假设我有一个简单的路线,人们可以在其中向另一个用户发布 PM:

@app.route('/admin/pm', methods=['GET', 'POST'])
@login_required
def pms():
    if request.method == 'POST':
        savePM(g.user.id, request.form['toUserId'], request.form['text'])
        # How do I emit a message here to the user to whom this message is sent?
    return render_template('sendPM.html')

我的评论已经说过:我如何向从那里发送此消息的用户发送消息?欢迎所有提示!

[编辑] 根据 Miguel 的提示,我想创建一个名称为 user.id 的房间,因此我现在创建了以下连接和断开连接事件:

@socketio.on('connect', namespace='/test')
@login_required
def websocketConnect():
    join_room(g.user.id)
    emit('my response', 'data': 'Connected', room=g.user.id)

@socketio.on('disconnect', namespace='/test')
@login_required
def websocketDisconnect():
    leave_room(g.user.id)
    print('Client disconnected')

但在连接后,我得到了下面的堆栈跟踪。 g对象不是用socketio路由创建的吗?

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/gevent/greenlet.py", line 327, in run
    result = self._run(*self.args, **self.kwargs)
  File "/Library/Python/2.7/site-packages/socketio/virtsocket.py", line 403, in _receiver_loop
    retval = pkt_ns.process_packet(pkt)
  File "/Library/Python/2.7/site-packages/socketio/namespace.py", line 164, in process_packet
    return self.call_method_with_acl('recv_connect', packet)
  File "/Library/Python/2.7/site-packages/socketio/namespace.py", line 240, in call_method_with_acl
    return self.call_method(method_name, packet, *args)
  File "/Library/Python/2.7/site-packages/socketio/namespace.py", line 282, in call_method
    return method(*args)
  File "/Library/Python/2.7/site-packages/flask_socketio/__init__.py", line 79, in recv_connect
    self.socketio._dispatch_message(app, self, 'connect')
  File "/Library/Python/2.7/site-packages/flask_socketio/__init__.py", line 137, in _dispatch_message
    ret = self.messages[namespace.ns_name][message](*args)
  File "/Library/Python/2.7/site-packages/flask_login.py", line 758, in decorated_view
    return func(*args, **kwargs)
  File "/Users/kramer65/repos/vg/app/views/webviews.py", line 418, in websocketConnect
    join_room(g.user.id)
  File "/Library/Python/2.7/site-packages/werkzeug/local.py", line 338, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: '_AppCtxGlobals' object has no attribute 'user'

【问题讨论】:

【参考方案1】:

我如何知道登录的人是否打开了网站并连接到 websockets?

由您来跟踪这一点。当用户连接到套接字端点时,您将收到connect 事件,您可以在此处将用户注册为已连接。连接事件处理程序可以访问session,因此如果登录用户将他们的 id 或昵称写入会话,您可以在套接字连接处理程序中访问它。

此外,当用户离开时,您会收到一个disconnect 事件。

如何向特定用户发送消息?

识别用户的最简单方法是将他们放在房间中,然后您可以向这些房间发送消息。如果您需要单独处理用户,那么只需将每个用户放在不同的房间中,以用户的昵称或 ID 命名。同样,管理用户房间的最佳位置是 connectdisconnect 事件处理程序。

不完全是你想要的,但我写了一个稍微复杂一点的使用房间的例子:

https://github.com/miguelgrinberg/Flask-SocketIO-Chat

【讨论】:

太棒了,教程大师本人的留言! :) 感谢您的解释。很高兴听到我可以使用 connect 事件来跟踪自己,这使得它更加灵活。只是关于房间的问题。创建一个房间“便宜”吗?例如,如果我有成千上万的用户,是否可以为每个人创建一个房间? 正如您在我最初问题的编辑中看到的那样,我现在编写了一个简单的connect 事件,但 g.object 似乎在 socketio 路由中不可用。如果我不知道哪个登录用户是尝试连接的用户,您知道如何为该用户创建房间吗? 没错,g 可用,但 before_request 处理程序不会针对套接字事件运行,因此填充 g 的代码没有机会运行,如文档所述。您必须将用户名或 ID 写入会话(可能在用户登录时),因为会话是在套接字事件处理程序中重新创建的。

以上是关于如何使用 websockets 通过 Flask 向特定用户发送消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何访问使用 websockets 发送的烧瓶中的 formData?Flask-SocketIO

通过 Websockets 从 Python Flask 服务器连续向客户端发送数据

如何在没有 Flask 的 Heroku 上托管 websocket 应用程序 python 服务器?

通过Websocket从Python Flask服务器连续向客户端发送数据

如何从 websocket 端点外部发出 websocket 消息?

flask使用websocket