项目班 08 WebSocket
app.py 更新 添加两个路由
??????handlers = [ ???????????(‘/‘, main.IndexHandler), ???????????(‘/explore‘, main.ExploreHandler), ???????????(‘/post/(?P<post_id>[0-9]+)‘, main.PostHandler), ???????????(‘/upload‘, main.UploadHandler), ???????????(‘/login‘, auth.LoginHandler), ???????????(‘/logout‘, auth.LogoutHandler), ???????????(‘/signup‘, auth.SignupHandler), ???????????(‘/room‘, chat.RoomHandler), ???????????(‘/ws‘, chat.ChatSocketHandler), ???????]
base.html 更新
{% block extra_scripts %}{% end %} #在body最后添加这一条
templates/message.html 添加HTML文件
<div class="message" id="m{{ message["id"] }}">{% module linkify(message["body"]) %}</div>
templates/room.html 添加聊天室html
{% extends ‘base.html‘ %}{% block title %}room page{% end %}{% block content %} ???<div id="body"> ?????<div id="inbox"> ???????{% for message in messages %} ?????????{% include "message.html" %} ???????{% end %} ?????</div> ?????<div id="input"> ???????<form action="/a/message/new" method="post" id="messageform"> ?????????<table> ???????????<tr> ?????????????<td><input name="body" id="message" style="width:500px"></td> ?????????????<td style="padding-left:5px"> ???????????????<input type="submit" value="提交"> ???????????????<input type="hidden" name="next" value="{{ request.path }}"> ?????????????</td> ???????????</tr> ?????????</table> ???????</form> ?????</div> ???</div>{% end %}{% block extra_scripts %}<script src="{{ static_url("js/chat.js") }}" type="text/javascript"></script>{% end %}
handlers/chat.py 添加聊天的handlers
import loggingimport tornado.escapeimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.websocketimport uuidfrom .main import AuthBaseHandlerclass RoomHandler(AuthBaseHandler): ???""" ???聊天室页面 ???""" ???def get(self): ???????self.render("room.html", messages=ChatSocketHandler.cache)class ChatSocketHandler(tornado.websocket.WebSocketHandler): ???waiters = set() ???# 等待接收信息的用户 ???cache = [] ????????# 存放消息 ???cache_size = 200 ??# 消息列表的大小 ???def get_compression_options(self): ???????""" 非 None 的返回值开启压缩 """ ???????return {} ???def open(self): ???????""" 新的WebSocket连接打开 """ ???????logging.info("new connection %s" % self) ???????ChatSocketHandler.waiters.add(self) #在集合中添加用户,出现相同用户会去重 ???def on_close(self): ???????""" WebSocket连接断开 """ ???????ChatSocketHandler.waiters.remove(self) #在集合中移除用户 ???@classmethod ???def update_cache(cls, chat): ???????"""更新消息列表,加入新的消息""" ???????cls.cache.append(chat) #列表中添加消息 ???????if len(cls.cache) > cls.cache_size: ???????????cls.cache = cls.cache[-cls.cache_size:] #如果列表长度大于200个元素,只显示最后200个元素 [-200:-1] ???@classmethod ???def send_updates(cls, chat): ???????"""给每个等待接收的用户发新的消息""" ???????logging.info("sending message to %d waiters", len(cls.waiters)) #logging类似于print,但又比print高级 ???????for waiter in cls.waiters: ???????????try: ???????????????waiter.write_message(chat) #给每个waiter发送消息 ???????????except: ???????????????logging.error("Error sending message", exc_info=True) ???def on_message(self, message): ???????""" WebSocket 服务端接收到消息 """ ???????logging.info("got message %r", message) ???????parsed = tornado.escape.json_decode(message) #通过json解码message ???????chat = { #创建一个chat字典,id为不重复的uuid字符串,body为上面json解码后的一个body ???????????"id": str(uuid.uuid4()), ???????????"body": parsed["body"], ???????} ???????chat["html"] = tornado.escape.to_basestring(self.render_string("message.html", message=chat)) ???????????????????????????#将chat赋给message,放入message.html里面渲染后变成一个html代码,然后通过tornado自带to_basestring方法 ???????????????????????????#转化为chat字典中html键的值;render_string只会返回字节流,需要用to_basestring来转化 ???????ChatSocketHandler.update_cache(chat) #执行更新消息列表函数 ???????ChatSocketHandler.send_updates(chat) #执行发送消息函数
static/js/chat.js 添加chat.js文件
$(document).ready(function() { ???if (!window.console) window.console = {}; ???if (!window.console.log) window.console.log = function() {}; ???$("#messageform").on("submit", function() { ?// 点击提交时执行 ???????newMessage($(this)); ???????return false; ???}); ???$("#messageform").on("keypress", function(e) { ?// 回车提交时执行 ???????if (e.keyCode == 13) { ???????????newMessage($(this)); ???????????return false; ???????} ???}); ???$("#message").select(); ???updater.start(); ??// 开始 WebSocket});function newMessage(form) { ????// 发送新消息给服务器 ???var message = form.formToDict(); ???updater.socket.send(JSON.stringify(message)); ???form.find("input[type=text]").val("").select();}jQuery.fn.formToDict = function() { ???var fields = this.serializeArray(); ???var json = {}; ???for (var i = 0; i < fields.length; i++) { ???????json[fields[i].name] = fields[i].value; ???} ???if (json.next) delete json.next; ???return json;};var updater = { ???socket: null, ???start: function() { ???????var url = "ws://" + location.host + "/ws"; ???????updater.socket = new WebSocket(url); ?// 初始化 WebSocket ???????updater.socket.onmessage = function(event) { ?// 获取到服务器的信息时响应 ???????????updater.showMessage(JSON.parse(event.data)); ???????} ???}, ???showMessage: function(message) { ???????var existing = $("#m" + message.id); ???????if (existing.length > 0) return; ???????var node = $(message.html); ???????// node.hide(); ???????$("#inbox").append(node); ?// 添加消息 DIV 到页面 ???????// node.toggle(); ???}};
项目班 08 WebSocket
原文地址:https://www.cnblogs.com/xuchengcheng1215/p/9218443.html