websocket 在tornodo与 javascript的交互过程

WebSocket是HTML5规范中新提出的客户端-服务器通讯协议,协议本身使用新的ws://URL格式。
WebSocket 是独立的、创建在 TCP 上的协议,和 HTTP 的唯一关联是使用 HTTP 协议的101状态码进行协议切换,使用的 TCP 端口是80,可以用于绕过大多数防火墙的限制。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端直接向客户端推送数据而不需要客户端进行请求,两者之间可以创建持久性的连接,并允许数据进行双向传送
Websocket 前端实现:
    // 验证成功之后执行此函数进行建立 websocket 连接!
    function callback(msg) {
        // id 指的是内存地址中的 id 值
        //mag succuses {"id": "139970284481672", "status": null, "encoding": "UTF-8"}
        if (msg.status) {
            status.text(msg.status);
            setTimeout(function () {
                btn.prop('disabled', false);
            }, 3000);
            return;
        }
        // 将 http 替换成 ws
        var ws_url = window.location.href.replace('http', 'ws'),
            join = (ws_url[ws_url.length - 1] === '/' ? '' : '/'),
            url = ws_url + join + 'ws?id=' + msg.id,
            //与服务器建立一个全双工通信!
            sock = new window.WebSocket(url),
            encoding = msg.encoding,
            terminal = document.getElementById('#terminal'),
            term = new window.Terminal({
                // 开启终端光标闪烁
                cursorBlink: true,
            });
        //ws://192.168.199.147:8888/ws?id=140136343186008
        // console.log(url);
        //UTF-8
        // console.log(encoding);
        wssh.sock = sock;
        wssh.term = term;

        term.on('data', function (data) {
            // console.log(data);
            sock.send(JSON.stringify({'data': data}));
        });

        // 连接建立好后的回调 此函数发生在 WebSocket 链接建立时
        sock.onopen = function () {
            $('.container').hide();
            term.open(terminal, true);
            term.toggleFullscreen(true);
        };

        // 收到服务器发送的消息后执行的回调
        sock.onmessage = function (msg) {
            var reader = new window.FileReader();

            reader.onloadend = function () {
                var decoder = new window.TextDecoder(encoding);
                var text = decoder.decode(reader.result);
                // console.log(text);
                term.write(text);
                if (!term.resized) {
                    resize_term(term, sock);
                    term.resized = true;
                }
            };
            reader.readAsArrayBuffer(msg.data);
        };
        // 此函数发生在通信过程有任何错误时
        sock.onerror = function (e) {
            console.log(e);
        };
        // 服务器关闭(连接关闭)触发这个事件!
        sock.onclose = function (e) {
            console.log(e);
            term.destroy();
            wssh.term = undefined;
            wssh.sock = undefined;
            $('.container').show();
            status.text(e.reason);
            btn.prop('disabled', false);
        };
    }
View Code
websocket 后端实现:
# Tornado提供支持WebSocket的模块是tornado.websocket,其中提供了一个WebSocketHandler类用来处理通讯。
class WsockHandler(MixinHandler, tornado.websocket.WebSocketHandler):

    def initialize(self, loop):
        # print(
        #     self.request
        # )
        # HTTPServerRequest(protocol='http', host='192.168.199.147:8888', method='GET', uri='/ws?id=140540949658424', version='HTTP/1.1', remote_ip='192.168.199.147')
        self.loop = loop
        self.worker_ref = None

    def get_client_addr(self):
        return self.get_real_client_addr() or self.stream.socket.getpeername()

    #  建立连接之后被调用!
    def open(self):
        # 返回元祖 地址和端口号!
        self.src_addr = self.get_client_addr()
        logging.info('Connected from {}:{}'.format(*self.src_addr))
        worker = workers.get(self.get_argument('id'))
        if worker and worker.src_addr[0] == self.src_addr[0]:
            # 移除 worker.id
            workers.pop(worker.id)
            self.set_nodelay(True)
            worker.set_handler(self)
            self.worker_ref = weakref.ref(worker)
            self.loop.add_handler(worker.fd, worker, IOLoop.READ)
        else:
            self.close(reason='Websocket authentication failed.')

    # 当客户端发送消息message过来时被调用,注意此方法必须被重写。
    def on_message(self, message):
        logging.debug('{!r} from {}:{}'.format(message, *self.src_addr))
        worker = self.worker_ref()
        try:
            msg = json.loads(message)
        except JSONDecodeError:
            return

        if not isinstance(msg, dict):
            return

        resize = msg.get('resize')
        if resize and len(resize) == 2:
            try:
                worker.chan.resize_pty(*resize)
            except (TypeError, struct.error, paramiko.SSHException):
                pass

        data = msg.get('data')
        if data and isinstance(data, basestring_type):
            worker.data_to_dst.append(data)
            worker.on_write()

    # 当WebSocket连接关闭后被调用。
    def on_close(self):
        '''在此函数之中,可以使用访问 self.close_code 和 self.close_reason 查询关闭的原因 '''
        logging.info('Disconnected from {}:{}'.format(*self.src_addr))
        worker = self.worker_ref() if self.worker_ref else None
        if worker:
            if self.close_reason is None:
                self.close_reason = 'client disconnected'
            worker.close(reason=self.close_reason)
View Code
websocket 后端说明:
#当一个WebSocket连接建立后被调用。
WebSocketHandler.open()
#当客户端发送消息message过来时被调用,注意此方法必须被重写。
WebSocketHandler.on_message(message)
#当WebSocket连接关闭后被调用
WebSocketHandler.on_close()
#向客户端发送消息messagea,message可以是字符串或字典(字典会被转为json字符串)。若binary为False,则message以utf8编码发送;二进制模式(binary=True)时,可发送任何字节码。
WebSocketHandler.write_message(message, binary=False)

#关闭WebSocket连接。
WebSocketHandler.close()
#判断源origin,对于符合条件(返回判断结果为True)的请求源origin允许其连接,否则返回403。可以重写此方法来解决WebSocket的跨域请求(如始终return True)。
WebSocketHandler.check_origin(origin)

 

posted @ 2018-08-19 22:06  十七楼的羊  阅读(151)  评论(0编辑  收藏  举报