HTML5 WebSocket
WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議。
WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。
在 WebSocket API 中,瀏覽器和服務器只需要做一個握手的動作,然后,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。
現在,很多網站為了實現推送技術,所用的技術都是 Ajax 輪詢。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP請求,然后由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源。
HTML5 定義的 WebSocket 協議,能更好的節省服務器資源和帶寬,並且能夠更實時地進行通訊。
瀏覽器通過 JavaScript 向服務器發出建立 WebSocket 連接的請求,連接建立以后,客戶端和服務器端就可以通過 TCP 連接直接交換數據。
當你獲取 Web Socket 連接后,你可以通過 send() 方法來向服務器發送數據,並通過 onmessage 事件來接收服務器返回的數據。
以下 API 用於創建 WebSocket 對象。
var Socket = new WebSocket(url, [protocol] );
以上代碼中的第一個參數 url, 指定連接的 URL。第二個參數 protocol 是可選的,指定了可接受的子協議。
WebSocket 屬性
以下是 WebSocket 對象的屬性。假定我們使用了以上代碼創建了 Socket 對象:
屬性 | 描述 |
---|---|
Socket.readyState | 只讀屬性 readyState 表示連接狀態,可以是以下值:
|
Socket.bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,但是還沒有發出的 UTF-8 文本字節數。 |
WebSocket 事件
以下是 WebSocket 對象的相關事件。假定我們使用了以上代碼創建了 Socket 對象:
事件 | 事件處理程序 | 描述 |
---|---|---|
open | Socket.onopen | 連接建立時觸發 |
message | Socket.onmessage | 客戶端接收服務端數據時觸發 |
error | Socket.onerror | 通信發生錯誤時觸發 |
close | Socket.onclose | 連接關閉時觸發 |
WebSocket 方法
以下是 WebSocket 對象的相關方法。假定我們使用了以上代碼創建了 Socket 對象:
方法 | 描述 |
---|---|
Socket.send() | 使用連接發送數據 |
Socket.close() | 關閉連接 |
WebSocket 實例
WebSocket 協議本質上是一個基於 TCP 的協議。
為了建立一個 WebSocket 連接,客戶端瀏覽器首先要向服務器發起一個 HTTP 請求,這個請求和通常的 HTTP 請求不同,包含了一些附加頭信息,其中附加頭信息"Upgrade: WebSocket"表明這是一個申請協議升級的 HTTP 請求,服務器端解析這些附加的頭信息然后產生應答信息返回給客戶端,客戶端和服務器端的 WebSocket 連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞信息,並且這個連接會持續存在直到客戶端或者服務器端的某一方主動的關閉連接。
Websocket 使用 ws 或 wss 的統一資源標志符,類似於 HTTPS,其中 wss 表示在 TLS 之上的 Websocket。如:
ws://example.com/wsapi wss://secure.example.com/
Websocket 使用和 HTTP 相同的 TCP 端口,可以繞過大多數防火牆的限制。默認情況下,Websocket 協議使用 80 端口;運行在 TLS 之上時,默認使用 443 端口。
一個典型的Websocket握手請求如下:
客戶端請求
GET / HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: example.com Origin: http://example.com Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ== Sec-WebSocket-Version: 13
服務器回應
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Location: ws://example.com/
- Connection 必須設置 Upgrade,表示客戶端希望連接升級。
- Upgrade 字段必須設置 Websocket,表示希望升級到 Websocket 協議。
- Sec-WebSocket-Key 是隨機的字符串,服務器端會用這些數據來構造出一個 SHA-1 的信息摘要。把 “Sec-WebSocket-Key” 加上一個特殊字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后計算 SHA-1 摘要,之后進行 BASE-64 編碼,將結果做為 “Sec-WebSocket-Accept” 頭的值,返回給客戶端。如此操作,可以盡量避免普通 HTTP 請求被誤認為 Websocket 協議。
- Sec-WebSocket-Version 表示支持的 Websocket 版本。RFC6455 要求使用的版本是 13,之前草案的版本均應當棄用。
- Origin 字段是可選的,通常用來表示在瀏覽器中發起此 Websocket 連接所在的頁面,類似於 Referer。但是,與 Referer 不同的是,Origin 只包含了協議和主機名稱。
- 其他一些定義在 HTTP 協議中的字段,如 Cookie 等,也可以在 Websocket 中使用。
在服務器方面,網上都有不同對websocket支持的服務器:
- php - http://code.google.com/p/phpwebsocket/
- jetty - http://jetty.codehaus.org/jetty/(版本7開始支持websocket)
- netty - http://www.jboss.org/netty
- ruby - http://github.com/gimite/web-socket-ruby
- Kaazing - https://web.archive.org/web/20100923224709/http://www.kaazing.org/confluence/display/KAAZING/Home
- Tomcat - http://tomcat.apache.org/(7.0.27支持websocket,建議用tomcat8,7.0.27中的接口已經過時)
- WebLogic - http://www.oracle.com/us/products/middleware/cloud-app-foundation/weblogic/overview/index.html(12.1.2開始支持)
- node.js - https://github.com/Worlize/WebSocket-Node
- node.js - http://socket.io
- nginx - http://nginx.com/
- mojolicious - http://mojolicio.us/
- python - https://github.com/abourget/gevent-socketio
- Django - https://github.com/stephenmcd/django-socketio
- erlang - https://github.com/ninenines/cowboy.git