zoukankan      html  css  js  c++  java
  • tornado-websocket

    WebSockets 允许浏览器和服务器之间进行 双向通信

     server端:

    class WebSocketHandler(WebBaseHandler):
        ''' websocket '''
        users = {} # {u'liubei': <handlers.message.message_handler.WebSocketHandler object at 0xb620b34c>,
                   #  u'rock': <handlers.message.message_handler.WebSocketHandler object at 0xb61794ec>}
    
        # ------------------提高部分 开始------------------
       # 提高部分只是细分发送信息的对象,不是很重要。完成提高部分结束后的 open,on_message, on_close即可。
    @classmethod def send_system_message(cls, self, content, send_type): """ :param self: 继承过websocket的base类的实例化对象,主要是self初始化了操作redis,mysql以及user对象的属性 :param content: 储存进redis的list data :param send_type: 发送的类型(发给boss,ceo,员工...),由前端传过来 :return: 系统消息,发送给每个人 """ target = 'system' redis_msg = cls.dict_to_json(self, content, send_type, target) self.conn.rpush('message:%s' % send_type, redis_msg) for f, v in WebSocketHandler.users.items(): v.write_message(redis_msg) @classmethod def dict_to_json(cls, self, content, send_type, target): """ :param self: 继承过websocket的base类的实例化对象,主要是self初始化了操作redis,mysql以及user对象的属性 :param content: 储存进redis的list data :param send_type: 发送的类型(发给boss,ceo,员工...),由前端传过来 :param target: 相当与用来区分缓存key的名字,比如 key_name="cache_list:%s"%target1, ...取对应分类的历史数据 :return: """ msg = { "content": content, "send_type": send_type, "sender": self.current_user.name, "target": target, "datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return tornado.escape.json_encode(msg) @classmethod def send_role_message(cls, self, content, send_type, roleid): """ :param self: :param content: :param send_type: :param roleid: 通过角色id,反查出属于该角色id的用户 :return: 发送信息给 该角色的所用用户 """ role = Role.by_id(roleid) redis_msg = cls.dict_to_json(self, content, send_type, role.name) self.conn.rpush('message:%s' % send_type, redis_msg) role_users = role.users # [zhangsan, lishi , wangwu] [zhangsan, lishi] for user in role_users: if WebSocketHandler.users.get(user.name, None) is not None: # user.name ['rock':self] WebSocketHandler.users[user.name].write_message(redis_msg) else: # self.conn.lpush("ws:role_off_line",message) pass @classmethod def send_user_message(cls, self, content, send_type, user): """ :param self: :param content: :param send_type: :param user: 发送的对象 :return: 发送信息给改用户 user """ redis_msg = cls.dict_to_json(self, content, send_type, user) self.conn.rpush('message:%s' % send_type, redis_msg) self.conn.rpush('message:%s' % user, redis_msg) # 为了显示未读消息条数 if cls.users.get(user, None) is not None: cls.users[user].write_message(redis_msg) else: # self.conn.lpush("ws:user_off_line",message) pass # ------------------提高部分 结束------------------ def open(self): ''' 有用户进来后,存储该用户 {usernaem: self} self是每个登录用户的实例化类 (用该实例化对象发送是那个消息) ''' WebSocketHandler.users[self.current_user.name] = self pass def on_message(self, message): # 改方法获取消息,前端通过 ws对象.send(msg)发送 # print message # {"content_html":"聊天框输入的内容"} json # {"content_html":"afaf<img src="/static/images/face/nm_thumb.gif" title="[怒骂]">"} msg = tornado.escape.json_decode(message) # 解码 json字符串 --> 字符串 msg.update({ "name": self.current_user.name, "datetime": datetime.now().strftime("%Y-%m-%d %H-%M-%S") }) message = tornado.escape.json_encode(msg) # 转成json self.conn.rpush('message:list', message) # 存储消息为了显示历史消息 # self.write_message(msg) # 就算不转成json,write_message也能自己编码 # WebSocketHandler.users['liubei'].write_message(message) # 这是将不管谁的message只发给用户liubei for f, v in WebSocketHandler.users.items(): v.write_message(message) def on_close(self): pass

    前端:和后端一样,都需要完成open,on_message,on_close三个方法

    <script type="text/javascript">
        $(document).ready(function(){
                //与服务器建立websocket链接请求
                var url="ws://" + location.host + "/ws";  //是open, on_message, on_close所在类映射的路由。是通过ws协议,而不是http 
                var ws= new WebSocket(url);//在浏览器打开一个socket  服务器打开一个socket
    
                ws.onopen=function(){
                    $('#status').text('已经建立链接');
                    var tishi = $('.tishi');
                    var name = tishi.attr('username');
                    tishi.append("<div>"+name+"加入了聊天室...</div>")
                };
    
                ws.onclose=function () {
                    $('#status').text('已经断开链接')
                };
    
                //当收到服务器向浏览器推送消息时调用这个函数
                ws.onmessage=function(event){
    
                    message = JSON.parse(event.data);
                  if(message.content_html){
                      append(message);
                  }else{
                      append_m(message);
                  }
                };
    
    
                //点出头像函数
                $('.t_gif').click(function(){
                    $('.t_box').toggle(300);
                });
    
                // 点击表情时把点击的表情添加到文本框中
                $('#q_ul li').click(function(){
                    var img = $(this).find("img").clone();
                    $(".t_input").append(img);
                    $(".t_input").focus();
                });
    
                // 点击发布按钮时调用wsbsocket.send()函数向服务器发送数据
                $(".t_btn").click(function(){
                    var content_html = $('.t_input').html();
                    console.log(content_html);
                    var massage = {
                        "content_html":content_html
                    };
                    ws.send(JSON.stringify(massage));
    
                });
    
                // 动态添加发布消息的函数
                function append(msg){
                    //向留言中添加消息
                    $(".t_all").prepend(function(n){
                        var content_html='';
                        var useravatar='';
                        var datetime1='';
                        if(msg){
                            content_html = msg.content_html;
                            var useravatar = 'defaut_avatar.jpeg';
                            datetime1 = msg.datetime;
                        }
                        return "<div class='t_list animated bounceIn'>"+
                                    "<div class='t_header'>"+
                                        "<img src='/static/images/useravatars/" + useravatar +"' alt='' width='64' height='64' />"+
                                    "</div>"+
                                    "<div class='t_icon'></div>"+
                                    "<div class='t_msg'>"+"<p style='font-size:8px;'>"+
                                    "<a class='name' href='#'>" +msg.name+ "&nbsp;&nbsp;&nbsp;</a>"+
                                        datetime1+"</p>"+content_html+"</div>"+
                                    "<div class='clear'></div>"+
                                "</div>"
                        });
                    $('.t_box').hide(400);
                    $('.t_input').text('');
                    $('.t_input').focus();
                }
    
    
                // 发布系统消息的函数
                function append_m(msg){
                    $(".system_all").html('');
                    var target = "";
                    if(msg.target == "system"){
                        target = "全体人员"
                    }else{
                        target = msg.target
                    }
                    var messages = "消息内容:"+msg.content+
                        "&nbsp;&nbsp;&nbsp;消息类型:"+
                        msg.send_type+"&nbsp;&nbsp;&nbsp;发送者:"+
                        msg.sender +"&nbsp;&nbsp;&nbsp;接收者:"+
                        target+"&nbsp;&nbsp;&nbsp;时间:"+
                        msg.datetime;
                    $(".system_all").html(messages);
                }
        })
    </script>

    参考中文文档:https://tornado-zh.readthedocs.io/zh/latest/websocket

  • 相关阅读:
    TrieTree的学习
    单调队列(monotonic queue)列与单调栈的学习
    507. Perfect Number
    157. Read N Characters Given Read4
    nsexec
    nsenter
    setjmp
    runc 测试
    cgo setns + libcontainer nsexec
    前端 导出为Excel 数据源为table表格 并且table中含有图片
  • 原文地址:https://www.cnblogs.com/tangpg/p/9505839.html
Copyright © 2011-2022 走看看