WebSocket 是用于浏览器与服务器之间进行双相连接的协议,可以用于创建基于浏览器的实时聊天工具。Tornado 自身 支持 WebSocket 协议 ,也可以用来接收网站管理员的编辑指令。
根据官方文档,可以通过继承 tornado.websocket.WebSocketHandler
处理来自 WebSocket 协议的请求:
class EchoWebSocket(tornado.websocket.WebSocketHandler): def open(self): print("WebSocket opened")
def on_message(self, message): self.write_message(u"You said: " + message)
def on_close(self): print("WebSocket closed")
重载的 open
、 on_message
、 on_close
方法分别用于处理连接创建时、接收信息时和连接关闭时的相关操作。对应的浏览器端操作为:
var ws = new WebSocket("ws://"+window.location.host+"/websocket"); ws.onopen = function() { ws.send("Hello, world"); }; ws.onmessage = function (evt) {
console.log(evt.data); };
首先需要创建聊天页面:
class ChatWebHandler(BaseController): def get(self): self.render("chat/index.html")
def post(self): # 登录用户信息存入 Cookie uid = self.get_body_argument("uid") self.set_secure_cookie("uid", uid) self.redirect("/chat") router = [ (r'/chat', ChatWebHandler), ]
如果是多人聊天,需要保存所有的请求对象,并在有消息进入时更新所有连接:
from datetime import datetime
class EchoWebSocket(tornado.websocket.WebSocketHandler): pool = set()
def open(self): EchoWebSocket.pool.add(self)
def on_close(self): EchoWebSocket.pool.remove(self)
def on_message(self, message): uid = self.get_secure_cookie("uid") uid = uid.decode() if uid is not None else "匿名" EchoWebSocket.update(dict( uid = uid, msg = message, t = datetime.now().strftime("%m-%d %H:%M:%S") ))
@classmethod def update(cls, msg): for chat in cls.pool: chat.write_message(msg) router = [ (r'/ws', WebSocketHandler), # WebSocket 地址为 ws://host/ws (r'/chat', ChatWebHandler) # 聊天室地址为 http://host/chat
]
浏览器客户端接收和发送消息:
$(document).ready(function(){
var input = $('#msgInput');
var frame = $('#msgFrame');
var wraper= $('#msgWraper');
var ws = new WebSocket("ws://" + window.location.host + "/ws");
// 发送消息 $('#msgForm').on('submit', function (e) {
var msg = input.val(); input.val(''); ws.send(msg);
return false; });
// 接收消息 ws.onmessage = function (evt) {
var data = JSON.parse(evt.data);
// 更新到界面 frame.append($('<li style="margin-left:12px;"><b>'+ data.uid+': </b>'+ data.message + '<span style="float:right; margin-right:12px;">' + data.t +'</span></li>'));
if (frame.height() >= wraper.height()) { wraper.scrollTop(frame.height()); }; }; });