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); }; }
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)
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)