python3 tornado +js+websoket实现多人聊天
首先先来认识一下websocket:
WebSocket API是下一代客户端-服务器的异步通信方法。该通信取代了单个的TCP套接字,使用ws或wss协议,可用于任意的客户端和服务器程序。 WebSocket目前由W3C进行标准化。WebSocket已经受到Firefox 4、Chrome 4、Opera 10.70以及Safari 5等浏览器的支持。
WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。WebSocket并不限于以Ajax(或XHR)方式通信,因为 Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允许跨域通信。
Ajax技术很聪明的一点是没有设计要使用的方式。WebSocket为指定目标创建,用于双向推送消息。
只专注于客户端的API,因为每个服务器端语言有自己的API。下面的代码片段是打开一个连接,为连接创建事件监听器,断开连接,消息时间,发送消息返回到服务器,关闭连接。
1 // 创建一个Socket实例 2 var socket = new WebSocket('ws://localhost:8080'); 3 // 打开Socket 4 socket.onopen = function(event){ 5 // 发送一个初始化消息 6 socket.send('I am the client and I\'m listening!'); 7 // 监听消息 8 socket.onmessage = function(event){ 9 console.log('Client received a message',event); 10 }; 11 // 监听Socket的关闭 12 socket.onclose = function(event){ 13 console.log('Client notified socket has closed',event); 14 }; 15 // 关闭Socket.... 16 //socket.close() 17 };
下面是一个完整的实例,加上了对用户的识别,首先是服务器端:
1 import logging 2 import tornado.escape 3 import tornado.ioloop 4 import tornado.options 5 import tornado.web 6 import tornado.websocket 7 import os.path 8 import uuid 9 10 from tornado.options import define, options 11 12 define("port", default=8888, help="run on the given port", type=int) 13 14 15 class Application(tornado.web.Application): 16 17 def __init__(self): 18 handlers = [ 19 (r"/", MainHandler), 20 (r"/websocket", ChatSocketHandler), 21 ] 22 settings = dict( 23 cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__", 24 template_path=os.path.join(os.path.dirname(__file__), "templates"), 25 static_path=os.path.join(os.path.dirname(__file__), "static"), 26 xsrf_cookies=True, 27 ) 28 tornado.web.Application.__init__(self, handlers, **settings) 29 30 31 class MainHandler(tornado.web.RequestHandler): 32 33 def get(self): 34 self.render("index.html", messages=ChatSocketHandler.cache) 35 36 37 class ChatSocketHandler(tornado.websocket.WebSocketHandler): 38 # 放置一个集合, 用来记录开启着的连接. 39 clients = set() 40 cache = [] 41 cache_size = 200 42 43 def allow_draft76(self): 44 # for iOS 5.0 Safari 45 return True 46 47 @staticmethod 48 # 给每一个客户端发送一个加入的信息。 49 def send_to_all(message): 50 for c in ChatSocketHandler.clients: 51 c.write_message(message) 52 53 def open(self): 54 print ("打开了新的客户端") 55 ChatSocketHandler.send_to_all(str(id(self)) + ' 加入聊天室!!!') 56 ChatSocketHandler.clients.add(self) 57 58 def on_close(self): 59 ChatSocketHandler.clients.remove(self) 60 61 @classmethod 62 def update_cache(cls, chat): 63 cls.cache.append(chat) 64 if len(cls.cache) > cls.cache_size: 65 cls.cache = cls.cache[-cls.cache_size:] 66 67 @classmethod 68 def send_updates(cls, chat): 69 logging.info("sending message to %d clients", len(cls.clients)) 70 for client in cls.clients: 71 try: 72 client.write_message(str(id(client)) + ':' + chat) 73 except: 74 logging.error("Error sending message", exc_info=True) 75 76 def on_message(self, message): 77 logging.info("got message %r", message) 78 79 ChatSocketHandler.send_updates(message) 80 81 82 def main(): 83 tornado.options.parse_command_line() 84 app = Application() 85 app.listen(8080) 86 tornado.ioloop.IOLoop.instance().start() 87 88 89 if __name__ == "__main__": 90 main()
客户端:
1 <html> 2 <head> 3 <title>Web Socket Client</title> 4 </head> 5 6 <body> 7 8 <script type="text/javascript"> 9 10 var socket; 11 12 if (!window.WebSocket) { 13 14 window.WebSocket = window.MozWebSocket; 15 16 } 17 18 // Javascript Websocket Client 19 20 if (window.WebSocket) { 21 22 socket = new WebSocket("ws://localhost:8080/websocket"); 23 24 socket.onopen = function(event) { 25 26 var ta = document.getElementById('responseText'); 27 28 ta.innerHTML = "Web Socket 打开!"; 29 30 }; 31 socket.onmessage = function(event) { 32 33 var ta = document.getElementById('responseText'); 34 35 ta.innerHTML = ta.innerHTML + "<br>" + event.data ; 36 37 }; 38 39 socket.onclose = function(event) { 40 41 var ta = document.getElementById('responseText'); 42 43 ta.innerHTML = ta.innerHTML + "Web Socket 关闭!"; 44 45 }; 46 47 } else { 48 49 alert("您的浏览器不支持 Web Socket."); 50 51 } 52 // Send Websocket data 53 54 function send() { 55 var message = document.getElementById("message").value; 56 if (!window.WebSocket) { return; } 57 if (socket.readyState == WebSocket.OPEN) { 58 59 socket.send(message); 60 61 } else { 62 63 alert("socket 没有打开."); 64 65 } 66 } 67 document.keydown = function (evt){ 68 var evt = windown.event?window.event:evt; 69 if(evt.keyCode == 13){ 70 send(); 71 } 72 } 73 74 </script> 75 76 <h4>接收消息 :</h4> 77 78 <div id="responseText" style="width:500px;height:300px;border:2px solid gray"></div> 79 <h4>发送消息 :</h4> 80 81 <input type="text" id="message" name="message" value="" placeholder="说点什么吧!!!"/> 82 <input type="button" value="发送" onclick="send()" /> 83 84 </body> 85 86 </html>
总结:虽然实现以后觉得是很简单的,但是过程是很享受的。
努力吧,为了媳妇儿,为了家。。。