tornado-websocket
2024-09-15 12:08:48
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+ " </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+
" 消息类型:"+
msg.send_type+" 发送者:"+
msg.sender +" 接收者:"+
target+" 时间:"+
msg.datetime;
$(".system_all").html(messages);
}
})
</script>
参考中文文档:https://tornado-zh.readthedocs.io/zh/latest/websocket
最新文章
- php artisan常用方法
- C++ 在Windows下截取整个屏幕 和 指定句柄窗口的屏幕
- String.format介绍
- iOS 9/10强制使用https访问网络,使用了第三方SDK的应用需要配置的信息
- zabbix安装全过程
- October 2nd 2016 Week 41st Sunday
- android: adapter getView(position==0) was invoked many times.
- Entity Framework CodeFirst尝试
- Halcon学习笔记之缺陷检测(二)
- 利用CCProxy管理小型企业的上网行为
- LightOj_1342 Aladdin and the Magical Sticks
- C random C ++rand函数应用
- ubuntu 下重装mysql若干问题
- Quartz.Net 使用
- 如何进行PDF页码编排,如何调整PDF页码顺序
- C#中FormsAuthentication用法实例
- docker[caffe&;&;pycaffe]
- Mysql 5.7.21 单机多实例安装
- 对象new和不new的理解
- (转)3款优秀的移动webAPP网站在线测试工具