项目班 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. Arc071_F Infinite Sequence

    传送门 题目大意 给定一个数$n$,构造一个无限长的序列$A$,使得 $\forall i,j\geq n,A_i=A_j$ $\forall i<j<k\leq i+a_i,A_j=A_ ...

  2. CH#24C 逃不掉的路 和 HDU3686 Traffic Real Time Query System

    逃不掉的路 CH Round #24 - 三体杯 Round #1 题目描述 现代社会,路是必不可少的.任意两个城镇都有路相连,而且往往不止一条.但有些路连年被各种XXOO,走着很不爽.按理说条条大路 ...

  3. bzoj 4631: 踩气球 线段树

    题目: Description 六一儿童节到了, SHUXK 被迫陪着M个熊孩子玩一个无聊的游戏:有N个盒子从左到右排成一排,第i个盒子里装着Ai个气球. SHUXK 要进行Q次操作,每次从某一个盒子 ...

  4. “Hello World”—— 第一个汇编程序

    Hello World这是每一门编程语言的第一个最简单程序,下面那个程序就是汇编语言的Hello World.学汇编一段时间了,到现在才记录下自己的第一个汇编程序笔记.虽然这是个相当简单的小程序,但这 ...

  5. 数据schemaAvro简介

    文章结束给大家来个程序员笑话:[M] 最近在研究Thrift和Avro以及它们的区分,通过各种渠道搜集资料,现整顿出有关Avro的一些资料,方便当前参考. 一.弁言 1. 简介 Avro是Hadoop ...

  6. HDOJ1728(限制转弯的迷宫问题)

    用bfs进行深搜,求出每个可达点的最小转弯数 #include<cstdio> #include<cstring> #include<queue> using na ...

  7. “在注释中遇到意外的文件结束”--记一个令人崩溃的bug

    下午写程序,写的好好的,突然报错"在注释中遇到意外的文件结束". 下面是官方给出的错误原因是缺少注释终结器 (* /). // C1071.cpp int main() { } / ...

  8. codeforces educational round25

    A #include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ; string s; c ...

  9. 16、GATK使用简介 Part1/2

    转载:http://blog.sina.com.cn/s/blog_6721167201018fyw.html GATK (全称The Genome Analysis Toolkit)是Broad I ...

  10. 第四课4、ROS客户端

    ROS客户端提供一些列库文件用于用户开发.它利用许多ROS概念并使它通过代码可以获取. 下面是ROS程序中的接口 ROSCPP客户端(c++客户端) 首先新建一个包 然后catkin_make一下 在 ...