前言
- tornado version 6.2
- 逻辑:
- 用户建立连接后创建单独的定时任务
- 在定时任务中进行消息推送服务(异步)
代码
import asyncio
import datetime
from loguru import logger as log
from concurrent.futures import ThreadPoolExecutor
from tornado.web import Application
from tornado.ioloop import PeriodicCallback
from tornado.websocket import WebSocketHandler
class MyThreadPool:
executor = ThreadPoolExecutor(max_workers=5)
class MyWsHandler(WebSocketHandler, MyThreadPool):
def data_received(self, chunk: bytes):
pass
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.event_loop = None
def check_origin(self, origin):
"""允许跨域请求"""
return True
def on_ping(self, data):
print("ping", data)
def on_pong(self, data):
print("pong", data)
if not data:
self.ping(str(round(datetime.datetime.now().timestamp() * 1000)))
def initialize(self):
"""为每个请求初始化"""
self.current_user = None
def prepare(self):
"""请求前置操作"""
pass
def open(self):
"""建立连接"""
log.info(f"建立连接: [{self.request.remote_ip}]-[{datetime.datetime.now()}]")
self.set_nodelay(True)
self.event_loop = PeriodicCallback(callback=self.send_message, callback_time=1000, jitter=0.5)
self.event_loop.start()
def on_message(self, message):
"""接收前端信息"""
print("msg:", message)
def on_close(self):
"""连接断开"""
log.info(f"连接断开: [{self.request.remote_ip}]-[{datetime.datetime.now()}]")
self.event_loop.stop()
async def send_message(self):
"""发送信息"""
await asyncio.sleep(0.5)
if self.ws_connection is None or self.ws_connection.is_closing():
self.close()
return
await self.write_message(str(datetime.datetime.now()))
class Main:
def __init__(self, debug=False):
self.debug = debug
self.urls = [
(r"/ws", MyWsHandler),
]
def mkApp(self):
return Application(
self.urls,
debug=self.debug,
websocket_ping_interval=5,
websocket_ping_timeout=20
)
async def admin(self, host, port):
app = self.mkApp()
app.listen(address=host, port=port)
await asyncio.Event().wait()
def run(self, host, port):
log.info(f"启动服务: {host}:{port}")
asyncio.run(self.admin(host=host, port=port))
if __name__ == '__main__':
Main(debug=True).run(host="0.0.0.0", port=12001)