一. WebSocket协议
WebSocket 协议本质上是一个基于 TCP 的协议。
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
由于这个规范目前还是处于草案阶段,版本的变化比较快,通常采用 draft-hixie-thewebsocketprotocol-76 版本来描述 WebSocket 协议,详情可访问 http://dev.w3.org/html5/websockets/。
二. Firefox的WebSocket实现1. 请求
GET /send HTTP/1.1Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Encoding: gzip, deflateAccept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3Cache-Control: no-cacheConnection: keep-alive, UpgradeHost: 127.0.0.1:8200Origin: http://127.0.0.1:8200Pragma: no-cacheSec-WebSocket-Key: KOySRTQgzqImO5s57OkTPA==Sec-WebSocket-Version: 13Upgrade: websocketUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:30.0) Gecko/20100101 Firefox/30.0
2. 应答
HTTP/1.1 101 Switching ProtocolsConnection: UpgradeSec-WebSocket-Accept: rr+f1d2NTgfAJeQ8t6/kzHli9ao=Upgrade: websocket
三. 基于Tornado3.1的WebSocket编程实现1.HTML示例注:基于jQuery、Bootstrap,同时将websocket.html保存在websocket.py同级的template目录下
<html><head> <link href="http://www.qmailer.net/archives/"http://cdn.bootcss.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"><link href="http://cdn.bootcss.com/bootstrap/3.2.0/css/bootstrap-theme.min.css" rel="stylesheet"><script src=""http://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="http://cdn.bootcss.com/bootstrap/3.2.0/js/bootstrap.min.js"></script><script> function send() { var ws = new WebSocket("ws://127.0.0.1:8200/send"); var data = { input:$("#input_data").val(), }; $("#message").empty(); ws.onopen = function() { ws.send(JSON.stringify(data)); }; $("#message").append(""'<div class="panel-body"><p>'); ws.onmessage = function(event) { $("#message").append(JSON.parse(event.data).input + "<br>"); }; ws.onclose = function(event) { $("#message").append('</p></div>'); };}</script></head><body> <div id="test"> <form class="form-horizontal" role="form"> <div class="panel panel-default"> <div class="panel-heading"> <h5 class="panel-title">>>输入</h5> </div> <div class="panel-body"> <div class="form-group"> <div class="col-md-8"> <input type="text" class="form-control" id="input_data" value=""> </div> </div> <div class="form-group"> <div class="col-md-8"> <button type="submit" class="btn btn-success" id="input_btn" onclick="send();">发送</button> </div> </div> </div> </div> </form> <div class="panel panel-default"> <div class="panel-heading"> <h5 class="panel-title">>> 输出</h5> </div> <div class="panel-body"> <div id="message"></div> </div> </div></body></html>
2.python示例
import osimport sysimport jsonimport timeimport tornado.httpserverimport tornado.webimport tornado.ioloopfrom tornado import websocketclass IndexHandler(tornado.web.RequestHandler): def get(self): self.render("websocket.html")class SendHandler(websocket.WebSocketHandler): clients = set() def open(self): SendHandler.clients.add(self) self.write_message(json.dumps({'input': 'connected...'})) self.stream.set_nodelay(True) def on_message(self, message): message = json.loads(message) self.write_message(json.dumps({'input': 'response...'})) i = 0 while i <= 10: i += 1 self.write_message(json.dumps(message)) time.sleep(1) # 服务器主动关闭 self.close() SendHandler.clients.remove(self) def on_close(self): # 客户端主动关闭 SendHandler.clients.remove(self)if __name__ == '__main__': app = tornado.web.Application( handlers=[ (r"/", IndexHandler), (r"/send", SendHandler) ], debug = False, template_path = os.path.join(os.path.dirname(__file__), "template"), static_path = os.path.join(os.path.dirname(__file__), "static") ) http_server = tornado.httpserver.HTTPServer(app, xheaders=True) http_server.listen(8200) tornado.ioloop.IOLoop.instance().start()
原文地址:Tornado编程-WebSocket原理及代码示例, 感谢原作者分享。 征服畏惧、建立自信的最快最确实的方法,