WebSocket
WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。
一、The WebSocket Handshake握手过程
- Client Handshake Request ------客户端握手请求,客户端发送get请求,样例如下:
1 GET /chat HTTP/1.1 2 Host: example.com:8000 3 Upgrade: websocket 4 Connection: Upgrade 5 Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== 6 Sec-WebSocket-Version: 13
2.Server Handshake Response------服务端握手响应
-
- 从请求【握手】信息中提取 Sec-WebSocket-Key
- 利用magic_string(258EAFA5-E914-47DA-95CA-C5AB0DC85B11) 和 Sec-WebSocket-Key 进行sha-1加密,再进行hash的base64编码
将加密结果响应给客户端
1 HTTP/1.1 101 Switching Protocols 2 Upgrade: websocket 3 Connection: Upgrade 4 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
一旦服务端发送类似上面的头部信息,握手完成,可以相互发送消息。
3.服务端跟踪客户端的socket。监听其连接状态
二、JavaScript类库实现客户端
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div> <input type="text" id="txt"/> <input type="button" id="btn" value="提交" onclick="sendMsg();"/> <input type="button" id="close" value="关闭连接" onclick="closeConn();"/> </div> <div id="content"></div> <script type="text/javascript"> var socket = new WebSocket("ws://127.0.0.1:8003/chatsocket"); socket.onopen = function () { /* 与服务器端连接成功后,自动执行 */ var newTag = document.createElement('div'); newTag.innerHTML = "【连接成功】"; document.getElementById('content').appendChild(newTag); }; socket.onmessage = function (event) { /* 服务器端向客户端发送数据时,自动执行 */ var response = event.data; var newTag = document.createElement('div'); newTag.innerHTML = response; document.getElementById('content').appendChild(newTag); }; socket.onclose = function (event) { /* 服务器端主动断开连接时,自动执行 */ var newTag = document.createElement('div'); newTag.innerHTML = "【关闭连接】"; document.getElementById('content').appendChild(newTag); }; function sendMsg() { var txt = document.getElementById('txt'); socket.send(txt.value); txt.value = ""; } function closeConn() { socket.close(); var newTag = document.createElement('div'); newTag.innerHTML = "【关闭连接】"; document.getElementById('content').appendChild(newTag); } </script> </body> </html>
# WebSocket 对象 提供到远程主机的双向通道。 # close 方法 关闭websocket。 # send 方法 使用websocket 发送数据到服务器。 # binaryType 属性 由 onmessage 接收的二进制数据格式。 # bufferedAmount 属性 使用 send 的已排队的数据字节数。 # extensions 属性 报告服务器所选中的扩展名。 # onclose 属性 当套接字关闭时调用的事件处理程序。 # onerror 属性 当出现错误时调用的事件处理程序。 # onmessage 属性 通知接收到消息的事件处理程序。 # onopen 属性 当 websocket 已连接时调用的事件处理程序。 # protocol 属性 报告服务器所选中的协议。 # readyState 属性 报告 websocket 连接的状态。 # url 属性 报告套接字的当前 URL。
三、Tornado的WebSocket实现聊天室
import uuid import json import tornado.ioloop import tornado.web import tornado.websocket class IndexHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') class ChatHandler(tornado.websocket.WebSocketHandler): # 用户存储当前聊天室用户 waiters = set() # 用于存储历时消息 messages = [] def open(self): """ 客户端连接成功时,自动执行 :return: """ ChatHandler.waiters.add(self) uid = str(uuid.uuid4()) self.write_message(uid) for msg in ChatHandler.messages: content = self.render_string('message.html', **msg) self.write_message(content) def on_message(self, message): """ 客户端发送消息时,自动执行 :param message: :return: """ msg = json.loads(message) ChatHandler.messages.append(message) for client in ChatHandler.waiters: content = client.render_string('message.html', **msg) client.write_message(content) def on_close(self): """ 客户端关闭连接时,,自动执行 :return: """ ChatHandler.waiters.remove(self) def run(): settings = { 'template_path': 'templates', 'static_path': 'static', } application = tornado.web.Application([ (r"/", IndexHandler), (r"/chat", ChatHandler), ], **settings) application.listen(8888) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Python聊天室</title> </head> <body> <div> <input type="text" id="txt"/> <input type="button" id="btn" value="提交" onclick="sendMsg();"/> <input type="button" id="close" value="关闭连接" onclick="closeConn();"/> </div> <div id="container" style="border: 1px solid #dddddd;margin: 20px;min-height: 500px;"> </div> <script src="/static/jquery-2.1.4.min.js"></script> <script type="text/javascript"> $(function () { wsUpdater.start(); }); var wsUpdater = { socket: null, uid: null, start: function() { var url = "ws://127.0.0.1:8888/chat"; wsUpdater.socket = new WebSocket(url); wsUpdater.socket.onmessage = function(event) { console.log(event); if(wsUpdater.uid){ wsUpdater.showMessage(event.data); }else{ wsUpdater.uid = event.data; } } }, showMessage: function(content) { $('#container').append(content); } }; function sendMsg() { var msg = { uid: wsUpdater.uid, message: $("#txt").val() }; wsUpdater.socket.send(JSON.stringify(msg)); } </script> </body> </html>
人,从刚出生来到这个世界,便开始探索这个世界。累了就歇会,精神了就继续探索,直至死亡。

浙公网安备 33010602011771号