为了账号安全,请及时绑定邮箱和手机立即绑定

我在tornado websocket服务器中哪里添加代码?

我在tornado websocket服务器中哪里添加代码?

噜噜哒 2023-06-27 13:32:31
我只是用“异步”和“线程”的基本知识进入 websocket 编程,我有这样的东西import tornado.httpserverimport tornado.websocketimport tornado.ioloopimport tornado.webimport socketimport uuidimport jsonimport datetimeclass WSHandler(tornado.websocket.WebSocketHandler):    clients = []    def open(self):        self.id = str(uuid.uuid4())        self.user_info = self.request.remote_ip +' - '+ self.id        print (f'[{self.user_info}] Conectado')        client = {"sess": self, "id" : self.id}        self.clients.append(client.copy())          def on_message(self, message):        print (f'[{self.user_info}] Mensaje Recivido: {message}')        print (f'[{self.user_info}] Respuesta al Cliente: {message[::-1]}')        self.write_message(message[::-1])        self.comm(message)     def on_close(self):        print (f'[{self.user_info}] Desconectado')        for x in self.clients:            if x["id"] == self.id :                self.clients.remove(x)    def check_origin(self, origin):        return Trueapplication = tornado.web.Application([    (r'/', WSHandler),])  if __name__ == "__main__":    http_server = tornado.httpserver.HTTPServer(application)    http_server.listen(80)    myIP = socket.gethostbyname(socket.gethostname())    print ('*** Websocket Server Started at %s***' % myIP)    tornado.ioloop.IOLoop.instance().start()我的问题是在哪里添加代码?我应该在 WShandler 类内部、外部或另一个文件中添加所有内容吗?以及何时使用@classmethod?目前,当我在处理程序中添加代码时,代码没有问题,但我只有很少的测试客户端。
查看完整描述

1 回答

?
慕桂英546537

TA贡献1848条经验 获得超10个赞

也许不是完整的解决方案,但只是一些想法..

第一个好的改变是,他们的客户(服务员)是一个 set() ,它确保默认情况下每个客户只包含一次。它作为类变量进行定义和访问。因此,您不使用 self.waiters 而是使用 cls.waiters 或 ClassName.waiters (在本例中为 ChatSocketHandler.waiters)来访问它。

class ChatSocketHandler(tornado.websocket.WebSocketHandler):
    waiters = set()

第二个变化是它们以 @classmethod 的形式更新每个客户端(您可以在此处选择将更新发送给部分客户端而不是全部客户端),因为它们不想接收实例(self)而是类(cls)并引用类变量(在本例中为 waiter、cache 和 cach_size)

我们可以在这里忘记缓存和缓存大小。

像这样:

@classmethod

    def send_updates(cls, chat):

        logging.info("sending message to %d waiters", len(cls.waiters))

        for waiter in cls.waiters:

            try:

                waiter.write_message(chat)

            except:

                logging.error("Error sending message", exc_info=True)

每次 API 调用时,都会创建处理程序的新实例,称为self. 并且中的每个参数self对于实例来说都是唯一的,并且与调用您的方法的实际客户端相关。这有助于在每次通话时识别客户。因此,基于实例的客户端列表(如 (self.clients))在每次调用时始终为空。添加客户端只会将其添加到该实例的世界视图中。

但有时您希望一些变量(例如客户端列表)对于从您的类创建的所有实例都相同。这就是类变量(直接在类定义下定义的变量)和@classmethod装饰器发挥作用的地方。

@classmethod使方法调用独立于实例。这意味着您只能访问这些方法中的类变量。但对于消息代理来说,这正是我们想要的:

  • 将客户端添加到类变量中,该变量对于处理程序的所有实例都是相同的。由于它被定义为一个集合,因此每个客户端都是唯一的。

  • 接收消息时,将其发送给所有(或一部分客户端)

  • soon_message是一个“正常”实例方法,但它调用类似:最后send_updates()是 a 。@classmethod

  • send_updates() 迭代所有(或子集)客户端(服务员)并最终使用它来发送实际更新。

从例子来看:

@classmethod

    def send_updates(cls, chat):

        logging.info("sending message to %d waiters", len(cls.waiters))

        for waiter in cls.waiters:

            try:

                waiter.write_message(chat)

            except:

                logging.error("Error sending message", exc_info=True)

请记住,您使用 waiters.append(self) 添加了服务员,因此每个服务员实际上都是一个实例,并且您“简单地”调用实例(该实例代表调用者) write_message() 方法。所以这不是广播,而是一一发送给每一个来电者。您可以在此处按某些标准(例如主题或组)进行分隔...


简而言之:用于@classmethod独立于特定实例(例如您的情况下的调用者或客户端)的方法,并且您希望对“所有”或“所有”客户端的子集执行操作。但您只能在这些方法中访问类变量。这应该没问题,因为这是他们的目的;)


查看完整回答
反对 回复 2023-06-27
  • 1 回答
  • 0 关注
  • 115 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信