最近使用tornado做長鏈接想着怎么着也要試試websocket協議吧。所以說干就干。
首先要知道websocket是基於http協議的,為什么這么說?因為從協議來說,websocket是借用了一部分為http請求頭信息來進行驗證和請求的的。
讓我們來看一個標准的websocket請求頭:
--- request header --- GET /chat HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: 127.0.0.1:8001 Origin: http://127.0.0.1:8001 Sec-WebSocket-Key: hj0eNqbhE/A0GkBXDRrYYw== Sec-WebSocket-Version: 13
可以看到使用http1.1 協議上面是標准的http的請求信息
method url http_protocol_versions
Host
Connection
但是熟悉http的小伙伴可以明顯看出這里多出了一些信息。用於實現協議升級
Upgrade: websocket
Connection: Upgrade
origin:xxxx
Sec-WebSocket-Key: hj0eNqbhE/A0GkBXDRrYYw== Sec-WebSocket-Version: 13
upgrade websocket用於告訴服務器此連接需要升級到websocket。
而下面的Sec-WebSocket-Key是客戶端也就是瀏覽器或者其他終端隨機生成一組16位的隨機base64編碼的串發上去這里貼上我在websocket-client 這個庫里面找到的生成這個key的函數。
def _create_sec_websocket_key(): randomness = os.urandom(16) return base64encode(randomness).decode('utf-8').strip()
最后Sec-WebSocket-Version就是當前使用協議的版本號了。
服務器在接受到上面的請求之后,會返回一個response 頭包完成握手。
HTTP/1.1 101 Switching Protocols Content-Length: 0 Upgrade: websocket Sec-Websocket-Accept: ZEs+c+VBk8Aj01+wJGN7Y15796g= Server: TornadoServer/4.5.1 Connection: Upgrade Date: Wed, 21 Jun 2017 03:29:14 GMT
由Sec-Websocket-Accept的key完成校驗。 我貼一個生成的Sec-Websocket-Accept的代碼大家感受一下
def compute_accept_value(key): """Computes the value for the Sec-WebSocket-Accept header, given the value for Sec-WebSocket-Key. """ sha1 = hashlib.sha1() sha1.update(utf8(key)) sha1.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") # Magic value return native_str(base64.b64encode(sha1.digest()))
這個入參key就是客戶端發上來的Sec_key。 然后服務器進行sha1計算並且拼上一個GUID RFC6455中可以找到這個字符串。然后進行base64encode返回給客戶端。客戶端拿到后拿自己的key做同樣的加密,如果對得上握手完成。到此為止就可以開始愉快的使用websocket進行交流了!
本文到這里就完了,如果要想了解websocket協議和傳統的long poll 和 short poll 之間的區別和使用場景,可以看下reference中的第一條。說得非常詳細和有趣。在本文就不贅述了。
Reference:
https://www.zhihu.com/question/20215561 WebSocket是什么原理,為什么可以實現持久連接。
https://tools.ietf.org/html/rfc6455 RFC6455