【问题标题】:Tornado: Identify / track connections of websockets?Tornado:识别/跟踪 websocket 的连接?
【发布时间】:2012-07-26 13:53:40
【问题描述】:

我有一个基本的 Tornado websocket 测试:

import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web

class WSHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        print 'new connection'
        self.write_message("Hello World")

    def on_message(self, message):
        print 'message received %s' % message

    def on_close(self):
      print 'connection closed'


application = tornado.web.Application([
    (r'/ws', WSHandler),
])


if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

我希望能够处理多个连接(它似乎已经这样做了)而且还能够引用其他连接。我看不到一种识别和跟踪单个连接的方法,只是为了能够处理连接打开、消息接收和连接关闭时的事件。

[编辑]
考虑创建一个字典,其中键是 Sec-websocket-key,值是 WSHandler 对象......想法?我不确定 Sec-websocket-key 的唯一性有多可靠。

【问题讨论】:

  • 据我所知,每个连接都会创建一个 WSHandler 实例。所以,WSHandlers 基本上只是连接接口。您是否想在网络之上添加一些消息处理引擎,例如code.google.com/p/pyscxml

标签: python websocket tornado


【解决方案1】:

最简单的方法就是保留一个 WSHandler 实例的列表或字典:

class WSHandler(tornado.websocket.WebSocketHandler):
    clients = []

    def open(self):
        self.clients.append(self)
        print 'new connection'
        self.write_message("Hello World")

    def on_message(self, message):
        print 'message received %s' % message

    def on_close(self):
        self.clients.remove(self)
        print 'closed connection'

如果您想识别连接,例如按用户,您可能必须通过套接字发送该信息。

【讨论】:

  • If you want to identify connections, e.g. by user, you'll probably have to send that information over the socket.。我不明白你在这里的意思?用户如何识别连接?
  • 一种方法(例如)是通过套接字发送会话 ID,在 on_message 中处理它,并将其存储在 WSHandler 实例(或任何地方)中。
  • @ColeMaclean 很好的答案!但是,如果在一个有多个用户的系统中,我想发送从一个也更新了数据库的 websocket 客户端(browser1)接收到的数据,并将该数据传递给另一个客户端(browser2)?
  • @direwolf7 您需要在on_message 中处理所有这些(或者最好调用其他的)
  • 我认为这里使用集合而不是列表更合适,以避免重复。
【解决方案2】:

Cole Maclean asnwer 非常适合作为简单的解决方案,当您只需要所有连接的列表时。 但是,如果您想要更复杂的东西,可以在 WSHandler 实例之外进行监控 - 勇敢地这样做:

class WSHandler(tornado.websocket.WebSocketHandler):

    def open(self):
        self.id = uuid.uuid4()
        external_storage[self.id] = {'id':self.id}
        print 'new connection'
        self.write_message("Hello World")

    def on_message(self, message):
        #Some message parsing here
        if message.type == 'set_group':
           external_storage[self.id]['group'] = message.group
        print 'message received %s' % message

    def on_close(self):
        external_storage.remove(self.id)
        print 'closed connection'

【讨论】:

  • Cole 的回答可以满足我的需要,但如果我确实需要在 WSHandler 本身之外进行更多控制,我会牢记您的回答。感谢您的帮助!
  • @Nikolay,Nikolay 的回答非常好,在不让他们发送他们是谁的情况下跟踪用户非常好,您可以轻松识别他们并相应地发送消息/关闭连接......好工作 :))。通常此类信息的存储是使用 Redis 完成的。
  • 绝对是处理这种情况的可靠方法。
  • 我真的可以将处理程序对象存储在像 memcached 这样的外部缓存中吗?我认为对象本身可以被序列化,但是它与连接相关联,我不确定它是否会丢失......
  • 如果我有多个 Tornado 服务器怎么办?我如何在他们和客户(浏览器)之间进行通信?
【解决方案3】:

如果您的用户有访问令牌,则可以将其附加到您的 websocket 端点,并在初始化您的套接字时获取,甚至在它打开之前(但请通过 SSL 工作)。

如果访问令牌不可用,无论是因为用户未提供访问令牌还是他们提供的令牌已过期,则用户未通过身份验证,您将尽早终止套接字。

无论您如何执行此操作,访问令牌都应该与拥有标识符的用户相关联,然后该标识符甚至可以在套接字打开之前绑定到套接字。标识符可以用作字典键,其值是与该用户绑定的一组套接字。

【讨论】:

    【解决方案4】:

    我已经通过检查 conexion 的来源解决了这个问题。因此,覆盖 def check_origin(self, origin) 方法可能会有所帮助。例如:

    clients = {}
    
    class WSHandler(tornado.websocket.WebSocketHandler):
    
    
        def check_origin(self, origin): 
    
            clients[origin] = self
            print(clients)
            return True
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-19
      • 1970-01-01
      相关资源
      最近更新 更多