Tornado WebSocket異步處理任務消息

一、客戶端代碼 test.html

用於模擬websocket 發送數據請求(新建html文件,粘貼如下代碼,並用谷歌瀏覽器打開)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      .wrapper {
        margin-top: 16px;
        margin-left: 30px;
        margin-bottom: 16px;
      }
      #addressBox {
        width: 400px;
        height: 30px;
      }
      .paramsLabel {
        margin-left: 30px;
      }
      #paramsBox {
        margin-left: 80px;
      }
      #sendBtn {
        margin-left: 30px;
      }
      #viewBox {
        width: 200px;
        height: 200px;
        border: 1px solid #ccc;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <label for="addressBox">socket地址</label>
      <input id="addressBox" type="text" value="ws://127.0.0.1:8000/debug/websocket" />
    </div>
    <label class="paramsLabel" for="paramsBox">socket參數</label>
    <div class="wrapper">
      <textarea id="paramsBox" cols="30" rows="10" placeholder="請輸入json數據"></textarea>
    </div>
    <button id="sendBtn">發送請求</button>
    <button id="closeBtn">關閉請求</button>

    <!-- 展示返回數據 -->
    <div id="viewBox" class="wrapper"></div>

    <script type="text/javascript">
      const addressBox = document.querySelector('#addressBox')
      const sendBtn = document.querySelector('#sendBtn')
      const paramsBox = document.querySelector('#paramsBox')
      const closeBtn = document.querySelector('#closeBtn')
      const viewBox = document.querySelector('#viewBox')

      var ws = null

      // 發送數據
      sendBtn.onclick = () => {
        var socket = addressBox.value
        ws = new WebSocket(socket)

        const params = paramsBox.value

        console.log(params)
        // 打開socket
        ws.onopen = function() {
          if (params) {
            ws.send(params)
          } else {
            ws.send(JSON.stringify({}))
          }
        }
        // 接收數據
        ws.onmessage = function(data) {
          viewBox.innerHTML = ''
          viewBox.innerHTML += JSON.stringify(data)
        }
      }

      // 關閉socket
      closeBtn.onclick = () => {
        ws.close(1000,2)
        ws.onclose = () => {
          console.log('關閉連接')
        }
      }
    </script>
  </body>
</html>
二、服務端

採用tornado websocket 自帶的類,處理ws請求;需改寫WebSocketHandler 中的on_message通信方法

import time
import tornado.web
import tornado.websocket
from tornado.ioloop import IOLoop
from tornado import gen
import tornado.options
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor


class ExecutorBase(object):
    executor = ThreadPoolExecutor(4)


class DebugWebsocket(tornado.websocket.WebSocketHandler, ExecutorBase):
    def check_origin(self, origin):
        """校驗權限"""
        return True

    def open(self):
        """開啓連接"""
        print("WebSocket opened")

    @gen.coroutine
    def on_message(self, message):
        """連接通信"""
        request_data = message
        resp = yield self.resp_time(request_data)
        self.write_message('resp:%s' % resp)

    def on_close(self):
        """關閉連接"""
        print("WebSocket closed")

    @run_on_executor
    def resp_time(self, request_data):
        # 異步執行延時操作 to do sth
        time.sleep(2)
        return time.time()


def make_app():
    """路由"""
    tornado.options.parse_command_line()
    return tornado.web.Application([
        (r"/debug/websocket", DebugWebsocket),
    ])


def start(port):
    """啓動"""
    app = make_app()
    app.listen(port=port)
    IOLoop.current().start()


if __name__ == '__main__':
    print('--start--')
    start(8000)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章