tornado 实现 websocket 服务

import asyncio
import datetime
import time
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, WebSocketClosedError


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
        self.request_message = None

    def check_origin(self, origin):
        """允许跨域请求"""
        return True

    def on_ping(self, data):
        print("ping", data)
        # self.ping(str(round(time.time() * 1000)))

    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)  # 设置无延迟
        # 单位毫秒,上下浮动50%
        self.event_loop = PeriodicCallback(callback=self.send_message, callback_time=1000, jitter=0.5)
        self.event_loop.start()

    def on_message(self, message):
        """接收前端信息"""
        self.request_message = message

    def on_close(self):
        """连接断开"""
        log.info(f"连接断开: [{self.request.remote_ip}]-[{datetime.datetime.now()}]")
        self.event_loop.stop()

    async def send_message(self):
        """发送信息"""
        log.info("接受的信息==>" + str(self.request_message))
        if not self.request_message:
            return
        await asyncio.sleep(1)
        if self.ws_connection is None or self.ws_connection.is_closing():
            self.close()
            return

        for i in range(100):
            time.sleep(1)
            try:
                await self.write_message(f"{i}")
            except WebSocketClosedError as e:
                print("连接断开")
                break


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,  # 间隔5秒发送一次ping帧,第一次发送为触发的5s后
            # websocket_ping_timeout=20   # 每次 ping 操作重置时间超时时间,若超时则断开连接,默认3次 ping 或 30s 断开
        )

    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="localhost", port=8765)

客户端使用 vue

<template>
    <div>
        <h2>websocket</h2>
        <button class="button" @click="send1()" >发送</button>
        <button class="button" @click="close()" >断开</button>
        <button class="button" @click="connect()" >连接</button>
        <div>
          <h2>来自服务端的消息: {{ msg }}</h2>
        </div>
    </div>
    

</template>
  

<script>
  export default {
    name: 'WebSocket',
    mounted () {
      this.initWebSocket();
    },
    data() {
        return {
          msg:""
        }
    },
    methods: {
      connect(){
        this.initWebSocket()
      },
      initWebSocket(){
        this.websocket = new WebSocket("ws://localhost:8765/ws?a=1");
        this.websocket.onmessage = this.websocketOnMessage;
        this.websocket.onopen = this.websocketOnOpen;
        this.websocket.onerror = this.websocketOnError;
        this.websocket.onclose = this.websocketOnClose;
        
      },
      close(){
        this.websocket.close()
      },
      websocketOnMessage(e){
        this.msg = e.data
        console.log("收到的消息",e.data);
      },
      websocketOnOpen(e){
        console.log("链接成功",e);
      },
      websocketOnError(e){
        console.log("连接失败",e);
        alert("连接失败")
      },
      websocketOnClose(e){
        console.log("断开连接");
        this.websocket.close()
      },
      send1(){
        this.websocket.send("来自 1号 的消息")
      }
    }
  };
</script>


<style>
  .button {
    /* width: 30px; */
    cursor: pointer;
    border-radius: 20px;
    /* border: 1px solid #ff4b2b;
    background: #ff4b2b; */
    /* border: 1px solid #fa8817;
    background: #fa8817; */
      border: 1px solid #1BBFB4;
    background: #1BBFB4;
    color: #fff;
    font-size: 12px;
    font-weight: bold;
    padding: 35px 45px;
    margin-top: 10%;
    letter-spacing: 1px;
    text-transform: uppercase;
    transition: transform 80ms ease-in;
  }
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值