• 项目 08 WebSocket


    项目班 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="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();
        }
    };
  • 相关阅读:
    isinstance函数
    Django之ORM那些相关操作
    Django ~ 2
    Django ~ 1
    Django详解之models操作
    Django模板语言相关内容
    livevent的几个问题
    客户端,服务器发包走向
    关闭客户端连接的两种情况
    std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义
  • 原文地址:https://www.cnblogs.com/xuchengcheng1215/p/9218443.html
Copyright © 2020-2023  润新知