python tornado websocket 多聊天室(返回消息给部分连接者)
python tornado 构建多个聊天室, 多个聊天室之间相互独立, 实现服务器端将消息返回给相应的部分客户端!
chatHome.py // 服务器端, 渲染主页 --》 聊天室建立websocket连接 --》 服务器端记录连接 --》 服务器端接收消息,判断聊天室,返回最新消息到对应聊天室
1 #-*-coding:utf-8-*- 2 __author__ = 'zhouwang' 3 import json 4 import tornado.web 5 import tornado.websocket 6 import tornado.httpserver 7 import tornado.ioloop 8 import tornado.options 9 from uuid import uuid4 10 11 class ChatHome(object): 12 ''' 13 处理websocket 服务器与客户端交互 14 ''' 15 chatRegister = {} 16 17 def register(self, newer): 18 ''' 19 保存新加入的客户端连接、监听实例,并向聊天室其他成员发送消息! 20 ''' 21 home = str(newer.get_argument('n')) #获取所在聊天室 22 if home in self.chatRegister: 23 self.chatRegister[home].append(newer) 24 else: 25 self.chatRegister[home] = [newer] 26 27 message = { 28 'from': 'sys', 29 'message': '%s 加入聊天室(%s)' % (str(newer.get_argument('u')), home) 30 } 31 self.callbackTrigger(home, message) 32 33 def unregister(self, lefter): 34 ''' 35 客户端关闭连接,删除聊天室内对应的客户端连接实例 36 ''' 37 home = str(lefter.get_argument('n')) 38 self.chatRegister[home].remove(lefter) 39 if self.chatRegister[home]: 40 message = { 41 'from': 'sys', 42 'message': '%s 离开聊天室(%s)' % (str(lefter.get_argument('u')), home) 43 } 44 self.callbackTrigger(home, message) 45 46 def callbackNews(self, sender, message): 47 ''' 48 处理客户端提交的消息,发送给对应聊天室内所有的客户端 49 ''' 50 home = str(sender.get_argument('n')) 51 user = str(sender.get_argument('u')) 52 message = { 53 'from': user, 54 'message': message 55 } 56 self.callbackTrigger(home, message) 57 58 def callbackTrigger(self, home, message): 59 ''' 60 消息触发器,将最新消息返回给对应聊天室的所有成员 61 ''' 62 for callbacker in self.chatRegister[home]: 63 callbacker.write_message(json.dumps(message)) 64 65 66 class chatBasicHandler(tornado.web.RequestHandler): 67 ''' 68 主页, 选择进入聊天室 69 ''' 70 def get(self, *args, **kwargs): 71 session = uuid4() #生成随机标识码,代替用户登录 72 self.render('chat/basic.html', session = session) 73 74 class homeHandler(tornado.web.RequestHandler): 75 ''' 76 聊天室, 获取主页选择聊天室跳转的get信息渲染页面 77 ''' 78 def get(self, *args, **kwargs): 79 n = self.get_argument('n') #聊天室 80 u = self.get_argument('u') #用户 81 self.render('chat/home.html', n=n, u=u) 82 83 84 class newChatStatus(tornado.websocket.WebSocketHandler): 85 ''' 86 websocket, 记录客户端连接,删除客户端连接,接收最新消息 87 ''' 88 def open(self): 89 n = str(self.get_argument('n')) 90 self.write_message(json.dumps({'from':'sys', 'message':'欢迎来到 聊天室(%s)' % n})) #向新加入用户发送首次消息 91 self.application.chathome.register(self) #记录客户端连接 92 93 def on_close(self): 94 self.application.chathome.unregister(self) #删除客户端连接 95 96 def on_message(self, message): 97 self.application.chathome.callbackNews(self, message) #处理客户端提交的最新消息 98 99 100 class Application(tornado.web.Application): 101 def __init__(self): 102 self.chathome = ChatHome() 103 104 handlers = [ 105 (r'/', chatBasicHandler), 106 (r'/home/', homeHandler), 107 (r'/newChatStatus/', newChatStatus), 108 ] 109 110 settings = { 111 'template_path': 'html', 112 'static_path': 'static' 113 } 114 115 tornado.web.Application.__init__(self, handlers, **settings) 116 117 if __name__ == '__main__': 118 tornado.options.parse_command_line() 119 server = tornado.httpserver.HTTPServer(Application()) 120 server.listen(8000) 121 tornado.ioloop.IOLoop.instance().start()
basic.html //主页, 选择进入聊天室, sessoin 设定为登录用户, GET: n指定聊天室, u指定用户
1 <body> 2 <h1>你好 !{{ session }} <br> 欢迎来到聊天室!</h1> 3 <a href="/home/?n=1&u={{ session }}"> 聊天室一 </a> <a href="/home/?n=2&u={{ session }}"> 聊天室二 </a> 4 </body>
home.html //聊天室,建立websocket连接,发送消息,接受消息,根据最新消息的发送者处理消息格式并写入页面
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 <script src="http://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script> 7 <script> 8 $(function(){ 9 n = $("#n").val() 10 u = $("#u").val() 11 12 $("#btn").click(function(){ 13 sendText() 14 }) 15 function requestText(){ 16 host = "ws://localhost:8000/newChatStatus/?n=" + n + "&u=" +u 17 websocket = new WebSocket(host) 18 19 websocket.onopen = function(evt){} // 建立连接 20 websocket.onmessage = function(evt){ // 获取服务器返回的信息 21 data = $.parseJSON(evt.data) 22 if(data['from']=='sys'){ 23 $('#chatinfo').append("<p style='width: 100%; text-align:center; font-size: 16px; color: green'>" + data['message'] + "</p>"); 24 }else if(data['from']==u){ 25 $('#chatinfo').append("<p style='width: 100%; text-align:right; font-size:15px'>" + u + ": <br>" +"<span style='color: blue'>" + data['message'] + "</span>" + "</p>"); 26 }else{ 27 $('#chatinfo').append("<p style='width: 100%; text-align:left; font-size:15px'>" + data['from'] + ": <br>" +"<span style='color: red'>" + data['message'] + "</span>" + "</p>"); 28 } 29 30 } 31 websocket.onerror = function(evt){} 32 } 33 34 requestText() // 开始 websocket 35 36 function sendText(){ // 向服务器发送信息 37 websocket.send($("#chat_text").val()) 38 } 39 }) 40 41 </script> 42 </head> 43 <body> 44 <div align="center"> 45 <div style="width: 70%"> 46 <h1>聊天室({{ n }})!</h1> 47 <input type="hidden" value="{{ n }}" id="n"> 48 <input type="hidden" value="{{ u }}" id="u"> 49 50 <div id="chatinfo" style="padding:10px;border: 1px solid #888"> 51 <!-- 聊天内容 --> 52 </div> 53 54 <div style="clear: both; text-align:right; margin-top: 20px"> 55 <input type="text" name="chat_text" id="chat_text"> 56 <button id="btn">发送</button> 57 </div> 58 </div> 59 </div> 60 </body> 61 </html>