3

我已经使用 sockjs-tornado 实现了聊天功能,并且可以将消息存储在 RethinkDB 中。

您能否帮助我了解如何在 sockjs-tornado 中建立用于消息传递的私人频道?(我的意思是私人谈话/一对一)

下面是我的服务器端代码中的 on_message 函数 -

def on_message(self, message):
    str=message
    mg=str.split('#:#')
    sender=1 # This is the sender user id
    receiver=2 #This is the receiver user id - I need to implement session variables to have these id's so that I can use it here this way
    ts=r.expr(datetime.now(r.make_timezone('00:00')))
    connection = r.connect(host="192.x.x.x")
    r.db("djrechat").table('events').insert({"usrs":mg[0],"msg":mg[1],"tstamp":ts,"snder":sender,"rcver":receiver}).run(connection)
    log.info(message)
    self.broadcast(self.participants, '{} - {}'.format(self.stamp(),message))

目前,这正在向所有连接的客户端广播。可能我应该有一个通道 id 并且只向两个具有相同通道 id 的客户端发送消息,但是我该如何实现它或者有没有更好的解决方案呢?

在客户端,我有以下 javascript -

      function connect() {
        disconnect();
        conn = new SockJS('http://localhost:8080/chat', ['websocket','xhr-streaming','iframe-eventsource','iframe-htmlfile','xhr-polling','iframe-xhr-polling','jsonp-polling']);
        //log('Connecting.....');
        conn.onopen = function() {
        //  log('Connected. (' + conn.protocol + ')');
        log('Connected.');
        };

        conn.onmessage = function(e) {
          log(e.data);
        };

        conn.onclose = function() {
          log('Disconnected.');
          conn = null;
        };
      }

我正在使用 python 3.4 - Django 1.8.4 和 Rethinkdb

4

2 回答 2

3

我的回答假设当前解决方案中的所有客户端都连接到 SockJS 服务器,其频道名称用于聊天消息的广播(或接近此场景的名称)。我进一步假设用户从客户端发送消息时的往返是:

[Sender (Client)] ------- Message (POST) --> [App Server] --- Message --> [Database]
                                                  |
                                               Message
                                                  v
[Receiver(s) (Client)] <-- Message (WS) -- [SockJS Server]

这个问题有多种解决方案。我只会在这里概述我认为最简单和最强大的一个:

  • 除了聊天中的广播频道外,让每个用户订阅每个用户(私人)频道。 如果您实施此解决方案,唯一的额外更改是让应用服务器了解必须发送到接收者的私人频道的私人消息。

另一个稍微复杂且不优雅的解决方案是在需要时为每个私有对创建临时通道。 但是,当您想与之聊天时,如何User B订阅(新创建的)私人频道?一种方法是广播连接到该频道的请求,但这会告诉所有其他客户端(在代码级别)将发生的私人聊天;如果这些客户端中的任何一个遭到入侵,则该信息可能会被滥用,例如窃听或破坏私人方。User AUser BUser B

附加建议

我还想提一下,自从我编写了我的sockjs - 实现房间答案的示例以来,我已经将自己的架构更改为(仍然)SockJS在前端使用,但是RabbitMQ在后端使用Web-STOMP 插件. 那样,

  1. 客户端仍然在浏览器中使用sockjs-clientstomp-websocket ,
  2. 可以删除处理前端多路复用 的所有后端代码,
  3. (基于 RabbitMQ 的)后端快速非常健壮
  4. 客户端向后端应用服务器发布一条消息,后端应用服务器反过来
    1. 将消息持久保存在数据库中,并且
    2. 充当 RabbitMQ 服务器的客户端,并且(1)将消息广播给所有连接的用户,或者如果消息是私有的 (2)通过接收者自己的私有通道将消息发送给单个接收者,如上文所述建议的解决方案。

整个新解决方案位于终止 HTTPS 和 SSL/TLS 加密的 WebSocket 连接的 HAProxy 后面。

于 2015-12-25T21:58:50.027 回答
1

尽管 sockjs-tornado 没有实现通道或房间之类的东西,但有一个示例多路复用如何实现它。另请查看sockjs - 实现房间的示例。解决方案基于结构化msg- 在您发送附加信息的消息中 - 频道名称。

于 2015-12-25T12:55:13.103 回答