我在哪里添加代码在龙卷风 websocket 服务器?
where do i add code in tornado websocket server?
我只是带着“异步”和“线程”的基本知识进入 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 class 内部还是外部,还是另一个文件中?什么时候使用@class方法?现在,当我在处理程序中添加代码时,代码没有问题,但我只有几个测试客户端。
可能不是完整的解决方案,只是一些想法..
你也许可以看看tornado websocket chat example,
here.
第一个好的变化是,他们的客户(服务员)是一个 set()
这确保默认情况下每个客户端只包含一次。它作为 class 变量定义和访问。因此,您不使用 self.waiters,而是使用 cls.waiters 或 ClassName.waiters(在本例中为 ChatSocketHandler.waiters)来访问它。
class ChatSocketHandler(tornado.websocket.WebSocketHandler):
waiters = set()
第二个变化是他们更新每个客户端(你可以在这里选择
以@class方法将更新发送给部分而不是全部,因为
他们不想接收实例 (self) 但 class (cls) 和
参考 class 变量(在他们的例子中,服务员、缓存和 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) 这样基于实例的客户端列表在每次调用时始终为空。添加客户端只会将其添加到此实例的世界视图中。
但有时您希望某些变量(例如客户端列表)对于从您的 class 创建的所有实例都相同。
这是 class 变量(您直接在 class 定义下定义的变量)和 @classmethod
装饰器发挥作用的地方。
@classmethod
使方法调用独立于 a 实例。这意味着您只能在这些方法中访问 class 变量。但在一个情况下
消息代理这正是我们想要的:
将客户端添加到 class 变量,这对于您的处理程序的所有实例都是相同的。并且由于它被定义为一个集合,每个客户端都是唯一的。
收到消息时,将它们发送给所有(或部分客户)
所以 on_message
是一个“普通”实例方法,但它调用类似的东西:send_updates()
最后是 @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
用于独立于特定实例(如您的情况下的调用者或客户端)的方法,并且您想对“全部”或“全部”的子集执行操作你的客户。但是您只能在这些方法中访问 class 变量。这应该没问题,因为这是他们的目的 ;)
我只是带着“异步”和“线程”的基本知识进入 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 class 内部还是外部,还是另一个文件中?什么时候使用@class方法?现在,当我在处理程序中添加代码时,代码没有问题,但我只有几个测试客户端。
可能不是完整的解决方案,只是一些想法..
你也许可以看看tornado websocket chat example, here.
第一个好的变化是,他们的客户(服务员)是一个 set() 这确保默认情况下每个客户端只包含一次。它作为 class 变量定义和访问。因此,您不使用 self.waiters,而是使用 cls.waiters 或 ClassName.waiters(在本例中为 ChatSocketHandler.waiters)来访问它。
class ChatSocketHandler(tornado.websocket.WebSocketHandler):
waiters = set()
第二个变化是他们更新每个客户端(你可以在这里选择 以@class方法将更新发送给部分而不是全部,因为 他们不想接收实例 (self) 但 class (cls) 和 参考 class 变量(在他们的例子中,服务员、缓存和 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) 这样基于实例的客户端列表在每次调用时始终为空。添加客户端只会将其添加到此实例的世界视图中。
但有时您希望某些变量(例如客户端列表)对于从您的 class 创建的所有实例都相同。
这是 class 变量(您直接在 class 定义下定义的变量)和 @classmethod
装饰器发挥作用的地方。
@classmethod
使方法调用独立于 a 实例。这意味着您只能在这些方法中访问 class 变量。但在一个情况下
消息代理这正是我们想要的:
将客户端添加到 class 变量,这对于您的处理程序的所有实例都是相同的。并且由于它被定义为一个集合,每个客户端都是唯一的。
收到消息时,将它们发送给所有(或部分客户)
所以
on_message
是一个“普通”实例方法,但它调用类似的东西:send_updates()
最后是@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
用于独立于特定实例(如您的情况下的调用者或客户端)的方法,并且您想对“全部”或“全部”的子集执行操作你的客户。但是您只能在这些方法中访问 class 变量。这应该没问题,因为这是他们的目的 ;)