项目班 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 logging
import tornado.escape
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket
import uuid from .main import AuthBaseHandler class 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的更多相关文章

  1. vue项目使用websocket做聊天项目总结

    一.首先我们先了解一下websocket的使用: 1.创建websocket const ws = new WebSocket("ws://192.168.31.136:9998/ws&qu ...

  2. maven项目添加websocket

    最近由于项目业务需求,需要用到websocket来实现即时信息的推送,学习了一下websocket,网上搜了一下学习教程,很多版本看的我云里雾里,最后选择用tomcat提供的最新版本(tomcat 启 ...

  3. vue项目使用websocket技术

    一.为什么需要websocket? 前端和后端的交互模式最常见的就是前端发数据请求,从后端拿到数据后展示到页面中.如果前端不做操作,后端不能主动向前端推送数据,这也是http协议的缺陷. 因此,一种新 ...

  4. HTML5学习总结-08 WebSocket 服务器推送

    一 WebSocket 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展 ...

  5. JAVAEE——BOS物流项目08:配置代理对象远程调用crm服务、查看定区中包含的分区、查看定区关联的客户

    1 学习计划 1.定区关联客户 n 完善CRM服务中的客户查询方法 n 在BOS项目中配置代理对象远程调用crm服务 n 调整定区关联客户页面 n 实现定区关联客户 2.查看定区中包含的分区 n 页面 ...

  6. Java web项目使用webSocket

    前端: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8&qu ...

  7. Go语言【项目】 websocket消息服务

    websocket消息服务 目的:搭建websocket服务,用浏览器与服务进行消息交互(写的第一个Go程序) 代码目录结构: 前端html页面: <!DOCTYPE html> < ...

  8. 开源项目 08 IOC Autofac

    using Autofac; using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

  9. AndroidAsync :异步Socket,http(client+server),websocket和socket.io的Android类库

    AndroidAsync是一个用于Android应用的异步Socket,http(client+server),websocket和socket.io的类库.基于NIO,没有线程.它使用java.ni ...

随机推荐

  1. log4net调试

    public delegate void LogReceivedEventHandler(object source, LogReceivedEventArgs e); public sealed c ...

  2. 洛谷【P2005】A/B Problem II

    题目传送门:https://www.luogu.org/problemnew/show/P2005 高精除低精:https://www.cnblogs.com/AKMer/p/9724556.html ...

  3. 利用dynamic来提供动态方法的性能

    前段时间做了一个worklist的项目,有部分是利用xml配置DICOM的tag,然后根据xml把DICOM的Dataset转为实体类,或者把实体类转为Dataset. 当中主要应用了反射来调用Dat ...

  4. a标签中href="javacript:;" href="javacript:void(0);" href="#"区别

    在使用<a>标签时,经常会绑定其他事件比如onclick,这时候我们会给<a>标签的href属性赋值为“#”,“javacript:;”,“javacript:void(0); ...

  5. POJ 2017 No Brainer(超级水题)

    一.Description Zombies love to eat brains. Yum. Input The first line contains a single integer n indi ...

  6. MySQL(介绍1)

    数据库(Database)是按照数据结构来组织.存储和管理数据的仓库: 也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢. 在WEB应用方面MySQL是最好的RDBMS(Relational ...

  7. LAMP 1.6 Discuz安装

    1.下载                                                                                                 ...

  8. qboimathtest1 t2 配对

    题目 有1~n一共n个数,n为偶数.小Q要把这n个数随机地两两配对.令每一对的权值为它们两个数的和.小Q想要知道这n/2对里最大的权值的期望是多少.请输出答案对10^9+7取模的值. [输入] 一行一 ...

  9. eos各表的关系

    在使用EOS WorkFlow的过程中,无论是开发者在“开发环境”中定义业务流程,还是“工作流引擎”控制流程流转,或是工作流参与者使用的“客户端”,再或者管理员使用的“管理与监控工具”,在这期间都会贯 ...

  10. 18. CTF综合靶机渗透(十一)

    靶机描述: SkyDog Con CTF 2016 - Catch Me If You Can 难度:初学者/中级 说明:CTF是虚拟机,在虚拟箱中工作效果最好.下载OVA文件打开虚拟框,然后选择文件 ...