首先認識HTML5的websocket:
在HTML5規范中,我最喜歡的Web技術就是正迅速變得流行的WebSocket API。WebSocket提供了一個受歡迎的技術,以替代我們過去幾年一直在用的Ajax技術。這個新的API提供了一個方法,從客戶端使用簡單的語法有效地推動消息到服務器。讓我們看一看HTML5的WebSocket API:它可用於客戶端、服務器端。而且有一個優秀的第三方API,名為Socket.IO。
什麼是WebSocket API?
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為指定目標創建,用於雙向推送消息。
關於web實時通信技術的發展(poll,ajax,comet等)以及websocket的介紹具體請參見:
使用 HTML5 WebSocket 構建實時 Web 應用 http://www.linuxidc.com/Linux/2012-02/54014.htm
鏈接的文章介紹了websocket的舊版協議草案,並用.net實現了該草案。
在2011年7月份,websocket發布了最新版的協議草案,草案的最新版本是草案10,草案的鏈接地址為:http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10,新的草案增加了安全性和可擴展性。
新草案客戶端與服務器端的握手協議:
客戶端發起websocket請求
[javascript]
- socket = new MozWebSocket("ws://localhost:12345/websocket/server.php")
這裡用的是firefox浏覽器,所以用MozWebSocket(),其他浏覽器像chrome,需要用WebSocket()
請求頭信息格式:
[plain]
- GET /chat HTTP/1.1
- Host: localhost:12345
- Upgrade: websocket
- Connection: Upgrade
- Sec-WebSocket-Key: kHuChwCCkr9PZDPWo+nMXg==
- Sec-WebSocket-Origin: http://localhost
- Sec-WebSocket-Protocol: websocket
- Sec-WebSocket-Version: 8
服務器端取得請求信息,主要是Sec-WebSocket-Key的值,取得該值之後,連接上字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11,然後計算其sha1散列值,生成一個20位的字符串,再對該字符串進行base64編碼,最後得到的值,按照下列響應信息格式返回給客戶端
[plain]
- HTTP/1.1 101 Switching Protocols
- Upgrade: websocket
- Connection: Upgrade
- Sec-WebSocket-Accept: 0VXXdxNQxqV7u7vtIhrxqdYUgRA=
- Sec-WebSocket-Protocol: websocket
客戶端接收到服務器的響應信息,連接建立。
新草案的數據傳輸格式請參考下文:
2、數據傳輸的格式:
以下是一個格式標准圖:
FIN:1位,用來表明這是一個消息的最後的消息片斷,當然第一個消息片斷也可能是最後的一個消息片斷;
RSV1, RSV2, RSV3: 分別都是1位,如果雙方之間沒有約定自定義協議,那麼這幾位的值都必須為0,否則必須斷掉WebSocket連接;
Opcode:4位操作碼,定義有效負載數據,如果收到了一個未知的操作碼,連接也必須斷掉,以下是定義的操作碼:
* %x0 表示連續消息片斷
* %x1 表示文本消息片斷
* %x2 表未二進制消息片斷
* %x3-7 為將來的非控制消息片斷保留的操作碼
* %x8 表示連接關閉
* %x9 表示心跳檢查的ping
* %xA 表示心跳檢查的pong
* %xB-F 為將來的控制消息片斷的保留操作碼
Mask:1位,定義傳輸的數據是否有加掩碼,如果設置為1,掩碼鍵必須放在masking-key區域,客戶端發送給服務端的所有消息,此位的值都是1;
Payload length: 傳輸數據的長度,以字節的形式表示:7位、7+16位、或者7+64位。如果這個值以字節表示是0-125這個范圍,那這個值就表示傳輸數據的長度;如果這個值是126,則隨後的兩個字節表示的是一個16進制無符號數,用來表示傳輸數據的長度;如果這個值是127,則隨後的是8個字節表示的一個64位無符合數,這個數用來表示傳輸數據的長度。多字節長度的數量是以網絡字節的順序表示。負載數據的長度為擴展數據及應用數據之和,擴展數據的長度可能為0,因而此時負載數據的長度就為應用數據的長度。
Masking-key:0或4個字節,客戶端發送給服務端的數據,都是通過內嵌的一個32位值作為掩碼的;掩碼鍵只有在掩碼位設置為1的時候存在。
Payload data: (x+y)位,負載數據為擴展數據及應用數據長度之和。
Extension data:x位,如果客戶端與服務端之間沒有特殊約定,那麼擴展數據的長度始終為0,任何的擴展都必須指定擴展數據的長度,或者長度的計算方式,以及在握手時如何確定正確的握手方式。如果存在擴展數據,則擴展數據就會包括在負載數據的長度之內。
Application data:y位,任意的應用數據,放在擴展數據之後,應用數據的長度=負載數據的長度-擴展數據的長度。
數據幀協議是按照擴展的巴科斯范式(ANBF:Augmented Backus-Naur Form RFC5234)組成的:
[plain]
- ws-frame = frame-fin
- frame-rsv1
- frame-rsv2
- frame-rsv3
- frame-opcode
- frame-masked
- frame-payload-length
- [ frame-masking-key ]
- frame-payload-data
-
- frame-fin = %x0 ; 表示這不是當前消息的最後一幀,後面還有消息
- / %x1 ; 表示這是當前消息的最後一幀
-
- frame-rsv1 = %x0
- ; 1 bit, 如果沒有擴展約定,該值必須為0
-
- frame-rsv2 = %x0
- ; 1 bit, 如果沒有擴展約定,該值必須為0
-
- frame-rsv3 = %x0
- ; 1 bit, 如果沒有擴展約定,該值必須為0
-
- frame-opcode = %x0 ; 表示這是一個連續幀消息
- / %x1 ; 表示文本消息
- / %x2 ; 表示二進制消息
- / %x3-7 ; 保留
- / %x8 ; 表示客戶端發起的關閉
- / %x9 ; ping(用於心跳)
- / %xA ; pong(用於心跳)
- / %xB-F ; 保留
-
- frame-masked = %x0 ; 數據幀沒有加掩碼,後面沒有掩碼key
- / %x1 ; 數據幀加了掩碼,後面有掩碼key
-
- frame-payload-length = %x00-7D
- / %x7E frame-payload-length-16
- / %x7F frame-payload-length-63
- ; 表示數據幀的長度
-
- frame-payload-length-16 = %x0000-FFFF
- ; 表示數據幀的長度
-
- frame-payload-length-63 = %x0000000000000000-7FFFFFFFFFFFFFFF
- ; 表示數據幀的長度
-
- frame-masking-key = 4( %0x00-FF ) ; 掩碼key,只有當掩碼位為1時出現
-
- frame-payload-data = (frame-masked-extension-data
- frame-masked-application-data) ; 當掩碼位為1時,這裡的數據為帶掩碼的數據,擴展數據及應用數據都帶掩碼
- / (frame-unmasked-extension-data
- frame-unmasked-application-data) ; 當掩碼位為0時,這裡的數據為不帶掩碼的數據,擴展數據及應用數據都不帶掩碼
-
- frame-masked-extension-data = *( %x00-FF ) ; 目前保留,以後定義
-
- frame-masked-application-data = *( %x00-FF )
-
- frame-unmasked-extension-data = *( %x00-FF ) ; 目前保留,以後定義
-
- frame-unmasked-application-data = *( %x00-FF )
上面是websocket的簡單介紹,以作備忘。