我只是带着“异步”和“线程”的基本知识跳到websocket编程中,我有这样的东西
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
import uuid
import json
import datetime
class 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 True
application = 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?。目前,当我在处理程序中添加代码时,代码没有问题,但是我只有很少的测试客户机
也许不是完整的解决方案,但只是一些想法
你可以看看tornado websocket聊天示例, here
第一个好的变化是,他们的客户(服务员)是一个集合() 这确保默认情况下每个客户端只包含一次。它是作为类变量定义和访问的。因此,您不使用self.waiters,而是使用cls.waiters或ClassName.waiters(在本例中是ChatSocketHandler.waiters)来访问它
第二个变化是它们更新每个客户机(您可以在这里选择) 将更新作为@classmethod发送给所有人(但仅发送给部分人),因为 他们不希望接收实例(self),但希望接收类(cls)和 参考类变量(在其情况下为waiters、cache和cach_size)
我们可以忽略缓存和缓存大小
所以像这样:
在每次API调用中,都会创建一个新的处理程序实例,称为
self
。而且self
中的每个参数对于实例来说都是唯一的,并且与调用方法的实际客户机相关。这有助于在每次通话中识别客户机。 因此,基于实例的客户端列表(self.clients)在每次调用时总是为空。添加客户机只会将其添加到该实例的世界视图中但有时您希望让一些变量(如客户机列表)与从类创建的所有实例相同。 这就是类变量(直接在类定义下定义的变量)和
@classmethod
装饰器发挥作用的地方@classmethod
使方法调用独立于a实例。这意味着您只能访问这些方法中的类变量。但是在一个 message broker这正是我们想要的:将客户端添加到类变量中,该变量对于处理程序的所有实例都是相同的。因为它被定义为一个集合,所以每个客户端都是唯一的
接收消息时,将其发送给所有(或客户端的子集)
所以
on_message
是一个“正常”的实例方法,但它调用类似于:send_updates()
的东西,这最终是一个@classmethod
send_updates()迭代所有(或一个子集)客户端(服务员),并最终使用它发送实际更新
从示例中可以看出:
请记住,您在waiters.append(self)中添加了waiters,因此每个waiter实际上都是一个实例,您只是“简单地”调用实例(该实例代表调用方)write_message()方法。所以这不是广播而是一个接一个地发送给每个来电者。这将是一个地方,你可以分开一些标准,如主题或组
简言之:对于独立于特定实例的方法(如本例中的调用方或客户端),使用
@classmethod
,并且您希望为“全部”或“全部”客户端的子集执行操作。但您只能访问这些方法中的类变量。这应该没问题,因为这是他们的目的;)相关问题 更多 >
编程相关推荐