在H5碱屁,js代碼新增了WebSocket的API掂咒。這玩意兒迹蛤,從使用上來說,不難仑扑,也就onopen、onclose置鼻、onmessage镇饮、onerror這幾個接口而已,前段時間使用的時候箕母,就還是不由自主地去看一些這方面的東西储藐。
Websocket是基于TCP協(xié)議上實現(xiàn)的,也有借助HTTP協(xié)議嘶是,但與HTTP1.X協(xié)議不同地方是钙勃,WebSocket是長連接,雙方只需要一個握手動作(這里是借助HTTP協(xié)議)聂喇,就可以建立一條連接通道辖源,接著就能相互傳輸數(shù)據(jù)了;而HTTP1.X是短連接的,每次發(fā)起請求都要在TCP層來個3次握手同木,數(shù)據(jù)傳輸完或到指定的超時時間后就斷開連接浮梢,若要多次請求,就要不斷發(fā)起請求彤路,這樣挺占帶寬秕硝。
Websocket在服務器方面,只需增加支持即可洲尊,如Python的tornado框架就支持远豺,golang也挺多的坞嘀,但我用的是大猩猩:gorilla。web服務器上,nginx在1.3.13版本也支持移必;其他web server,自行去搜索吧憎瘸。瀏覽器方面除了老IE系幌甘,其他瀏覽器目前的新版本基本都支持WebSocket线婚。
Javascript的接口
var conn = new WebSocket("ws://ip:port/");
conn.onclose = function(evt) {
console.log(evt);
}
conn.onmessage = function(evt) {
console.log(evt);
}
conn.onopen = function(evt) {
console.log(evt);
}
conn.onerror = function(evt) {
console.log(evt);
}
各接口看名稱就知道是什么意思了泪姨。
瀏覽器與服務端建立連接的時候,要經(jīng)過一個Websocket握手協(xié)議
GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 172.16.1.11
Origin: http://example.com
Sec-WebSocket-Key: BVuKSx8KJKN2VAGM0i6gjw==
Sec-WebSocket-Version: 13
這是正常的HTTP的GET請求,然后在請求頭里增加了
Upgrade: websocket
Connection: Upgrade
這等于告訴web服務器,發(fā)起的請求是Websocket協(xié)議的,要用Websocket協(xié)議方式來處理請求。
在請求頭里,還增加了
Sec-WebSocket-Key: BVuKSx8KJKN2VAGM0i6gjw==
看值的話替蛉,就應該能猜到它浅,是通過BASE64編碼而成的值典唇,這是瀏覽器隨機生成的。
HTTP響應頭
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: sr0Tsn4bYggO1mzRZHpiOQO+FYE=
Sec-WebSocket-Accept這個是通過服務器確認寒波,并加密后的Sec-WebSocket-Key级野。下面的這個響應頭代表告訴客戶端,升級成Websocket協(xié)議懒闷,屬于HTTP最后負責地方。
Upgrade: websocket
Connection: Upgrade
為什么說是HTTP最后負責的地方?因為WebSocket只是借助了HTTP協(xié)議去握手昔园,僅此而已蔓榄。此后信息通訊時,并不基于HTTP協(xié)議默刚,而是基于更底層的TCP協(xié)議甥郑。WebSocket是一個和HTTP協(xié)議一樣是基于TCP協(xié)議上的應用層協(xié)議。
數(shù)據(jù)收發(fā)
Websocket是可以發(fā)數(shù)據(jù)類型消息荤西,也可以發(fā)控制類型消息澜搅。
數(shù)據(jù)類型消息包含:純文本消息,二進制消息
控制類型消息包含:Ping邪锌,Pong勉躺,Close
更準確的說,WebSocket消息傳輸包含數(shù)據(jù)幀和控制幀觅丰,控制幀包含Ping饵溅,Pong,Close
這3個幀的Opcode各不相同:
- Ping幀的Opcode是9舶胀,0x09
- Pong幀的Opcode是10概说,0x0A
- Close幀的Opcode是8碧注,0x08
數(shù)據(jù)幀包含文本幀和二進制幀
- 文本幀的Opcode是1,0x01
- 二進制幀的Opcode是2糖赔,0x02
還有一個既非數(shù)據(jù)幀萍丐,也非控制幀,是0x00放典,代表繼續(xù)幀逝变。
通過上面幾個數(shù)字看到,還缺了幾個數(shù)字奋构,這幾個缺了的數(shù)字是協(xié)議保留壳影,以備后用。
保留幀
- 0x03——0x07:保留用于未來的非控制幀
- 0x0B——0x0F:保留用于未來的控制幀
還有其他的具體解釋在:傳送門
ping幀的數(shù)據(jù)傳輸
可以看到opcode是數(shù)字9
pong幀的數(shù)據(jù)傳輸
可以看到opcode是數(shù)字10
close幀
下圖是服務器主動斷開連接弥臼,opcode為10宴咧,在紅框處,有一個十六進制的數(shù)字径缅,還有一串英文解釋掺栅。
第一個Close表示的是關閉的代碼,第二個Close表示的是關閉的原因纳猪。
關閉的reason也可以自定義氧卧,但reason內(nèi)容的長度別過長(之前試過大概在128個字節(jié)左右,具體的可以再試試)氏堤,否則數(shù)據(jù)傳輸不了導致無法斷開的問題沙绝。
websocket的狀態(tài)碼具體詳解在這:傳送門
在js的接口中,沒有主動發(fā)起ping接口的調(diào)用鼠锈,這一般是在服務器那發(fā)起ping請求闪檬,瀏覽器接收到ping幀后,就會回個pong幀脚祟,從而達到心跳效果谬以。
發(fā)送文本數(shù)據(jù)
從web界面向服務器發(fā)送32個‘f’强饮,截取傳輸數(shù)據(jù)如下圖:
Payload length代表數(shù)據(jù)長度由桌。以字節(jié)的形式表示:7位、7+16位邮丰、或者7+64位行您。如果這個值以字節(jié)表示是0-125這個范圍,那這個值就表示傳輸數(shù)據(jù)的長度剪廉;如果這個值是126娃循,則隨后的兩個字節(jié)表示的是一個16進制無符號數(shù),用來表示傳輸數(shù)據(jù)的長度斗蒋;如果這個值是127,則隨后的是8個字節(jié)表示的一個64位無符號數(shù)捌斧,這個數(shù)用來表示傳輸數(shù)據(jù)的長度笛质。多字節(jié)長度的數(shù)量是以網(wǎng)絡字節(jié)的順序表示。負載數(shù)據(jù)的長度為擴展數(shù)據(jù)及應用數(shù)據(jù)之和捞蚂,擴展數(shù)據(jù)的長度可能為0,因而此時負載數(shù)據(jù)的長度就為應用數(shù)據(jù)的長度妇押。Payload length不包括Masking-key在內(nèi)。
Masking-key姓迅,呃敲霍,掩碼鍵。
還有好多其他說明丁存,都去傳送門里看吧肩杈。。
其他
之前在網(wǎng)上無意間看到這圖解寝,覺得挺不錯的扩然,描述建立連接時,websocket和TCP層的握手關系聋伦,很一目了然
在建立建立之后与学,每次端對端之間發(fā)送數(shù)據(jù),另一端在TCP層都會回發(fā)個ACK表示確認嘉抓。
WebSocket只是個協(xié)議索守,不是只能運行在瀏覽器上,自行用手機/其他客戶端也可以實現(xiàn)抑片,只需遵循協(xié)議即可(目前協(xié)議文檔是RFC6455)卵佛,個人覺得,假如沒有其他更好想法敞斋,用這個協(xié)議來代替很多TCP層的數(shù)據(jù)傳輸格式也是不錯的截汪。
還有一個是IBM公司搞的MQTT協(xié)議,之前了解過其主要用于嵌入式設備植捎,說是比較省電(相對于HTTP協(xié)議來比較那的確是)衙解,使用發(fā)布/訂閱消息模式,提供一對多的消息發(fā)布焰枢,解除應用程序耦合蚓峦。它跟Websocket一樣也是基于TCP協(xié)議的,都有各自的協(xié)議頭格式济锄。
呃暑椰,網(wǎng)上搜的時候,很多人都有對這些方面研究了荐绝,解釋的更好
張善友