大體瞭解下websocket

背景

當websocket並不存在本身的知識範圍內,前端如何保證獲取的數據和後端保持同步?傳統作法通常有兩種:http輪詢,Commet推送。那麼,這兩種方式有何不妥呢?html

HTTP輪詢

使用輪詢的方法,在設定的時間間隔,客戶端向服務端發送http請求,獲取服務端最新的數據。前端

Comet推送

Comet推送技術,服務器實時地將信息傳遞給客戶端,Comet是經過長輪詢或者iframe流實現的。web

長輪詢:在打開了一條鏈接後,在服務端推送了數據過來後才關閉。ajax

iframe流:將一隱藏的iframe插入頁面,利用iframe的src屬性,在客戶端和服務端創建一條長鏈接,服務端向iframe傳送數據(一般HTML,內有負責插入信息的js),實時更新頁面。googletalk使用的就是這種方法。chrome

不妥

  • HTTP請求每次都要攜帶完整(包含協議控制的數據包)的頭部,開銷有點大。
  • HTTP輪詢中,服務端須要接收到客戶端的請求,才能發送實時數據給客戶端,實時性仍是不夠強。
  • HTTP是無狀態協議,也就意味着,每次發送請求時,客戶端須要攜帶狀態信息,可能時候請求參數的數據都不及這些狀態信息的體積大。
  • Comet,依然須要反覆發出請求,並且採用的是長連接(是使用同一個tcp鏈接來發送和接收多個HTTP請求/應答,而不是爲每個新的請求/應答打開新的鏈接的方法,connection: keep-alive,Apache默認保持15秒),消耗服務器資源(對於單個文件被不斷請求的服務(例如圖片存放網站),Keep-Alive可能會極大的影響性能,由於它在文件被請求以後還保持了沒必要要的鏈接很長時間)。

websocket

備受矚目的websocket橫空出世,解決了一系列問題,使用起來也是極爲方便的。 websocket是一個基於TCP的全雙工通訊協議,HTTP同樣,都是一種處於應用層的通訊協議,並非什麼特別存在的協議。websocket使用的是ws或者wss的統一資源標識符,寫法和http的類似:後端

http://a.b.com/xxx
https://secure.b.com/xxx

ws://a.b.com/wsapi
wss://secure.b.com/
複製代碼

在websocket的世界,實時通訊相對來講不那麼難了。服務端和客戶端完成一次握手後,創建了一次持久性的鏈接,彼此能夠主動向對方發送實時信息。 websocket相比於傳統方式,有哪些優點呢?api

  • 實時性較強,服務端可隨時主動向客戶端推送信息。
  • 保持鏈接狀態,創建鏈接後的每次通訊,能夠省略攜帶狀態信息。
  • 支持二進制
  • 更好的壓縮效果

經常使用api

在前端,經過ajax發送HTTP請求。而websocket則是經過Websocket構造函數,傳入符合websocket規範的url,建立一個實例,創建鏈接,這個實例自己含有多個可供開發者調用的api。安全

構造函數Websocket

const socket = new Websocket('ws://examp.b.com');
複製代碼

屬性

  • onopen 監聽事件,當websocket鏈接創建,能夠收發數據。
socket.onpen = (event) => {
    console.log('the websocket is opened now');
}
複製代碼
  • onmessage 監聽事件,當websocket收到信息時觸發。
socket.onmessage = (event) => {
    console.log('the websocket receive data');
}
複製代碼
  • onclose 監聽事件,當websocket關閉時
socket.onclose = (event) => {
    console.log('the websocket is closed');
}
複製代碼
  • readyState websocket狀態:0(CONNECTING正在創建鏈接),1(OPEN,鏈接打開,能夠收發信息), 2(CLOSING正在關閉鏈接), 3(CLOSED鏈接關閉)
console.log(socket.readyState);
複製代碼
  • bufferedAmount 表示還有多少字節的二進制數據沒有被髮送出去,通常能夠用來判斷數據是否發送完成,畢竟,目前沒有一個能夠監聽數據發送是否完成的函數存在。
console.log(socket.bufferAmount)
複製代碼

方法

  • send 發送信息,發送的信息能夠string,blob,ArrayBuffer.
socket.send('hello')
複製代碼
  • close  主動關閉websocket鏈接.傳遞的參數有兩個,code, reason。 第一個參數爲code(number類型),解釋socket關閉的緣由(code),若不傳code,默認code的值爲1005,代表無code能夠傳。 第二個參數reason(string類型),人爲解釋關閉的緣由,字符串的字節長度不能超過UTF-8文本的123個字節。
socket.close(code, reason);
複製代碼

Websocket鏈接的建立過程

都說websocket都是一個基於TCP的全雙工通訊協議,websocket有何關係?一樣做爲應用層的通訊協議,除了上述的區別以外,websocket和http有什麼聯繫?這些可從websocket鏈接的建立過程得知。服務器

計算機網絡的五層模型:物理層、鏈路層、網絡層、傳輸層、應用層。TCP是傳輸層協議,websocket是應用層協議,創建websocket鏈接的過程當中,一定要通過傳輸層,因此,在創建鏈接以前,仍是須要通過TCP的三次握手。websocket

在TCP三次成功握手以後,意味着服務端和客戶端能夠進行信息的傳輸,這時候,使用websocket協議傳遞信息仍是不能夠的,須要客戶端向服務端發送HTTP請求,表示客戶端但願雙方使用websocket協議來進行通訊。在此次握手後,雙方能夠經過websocket協議主動向對方發送信息。下面這兩段來自於RFC。

  • 客戶端發送升級爲websocket協議的請求
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
複製代碼

在客戶端發送的這個特殊的HTTP請求中,有幾個特殊的字段: Upgrade:websocket,Connection: Upgrade這兩組鍵值對代表客戶端請求升級到websocket通訊協議。 Sec-webSecket-version,採用的websocket協議版本。

  • 服務器返回贊成升級爲websocket協議的信息
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
複製代碼

響應信息的第一行,狀態碼爲101,服務端根據客戶端的請求切換協議,服務端也返回了Upgrade:websocket,Connection: Upgrade,服務端將切換到websocket協議。

同時,能夠看到客戶端請求攜帶了Sec-websocket-key,這是一個由客戶端產生的一個base64編碼的隨機字符串,這個字符串和服務端返回的Sec-Websocket-Accept字段有着密切的聯繫。這二者用戶保護websocket通訊的安全性。在服務端收到來自客戶端開始的握手後,將客戶端攜帶的Sec-websocket-key和全局惟一一個標識符258EAFA5-E914-470A-95CA-C5ABOdc85b11結合,而後加密,做爲Sec-websocket-Accept的值返回給客戶端。那這麼作的意義是什麼呢?

服務端向客戶端證實本身收到了來自他的websocket握手,服務端將再也不接受來自客戶端的其餘非websocket通訊(指的是基於此次tcp鏈接和websocket握手完成後的通訊,並不針對客戶端和服務端之間全部的接口通訊)。這麼作有什麼好處呢?服務端將可避免攻擊者使用XMLHttpRequest或者表單提交發送精心設計的包來進行攻擊。固然,並不意味者websocket通訊絕對安全,就像http對應還有一個相對安全的https,ws還有一個相對來講比較安全的wss。

抓包分析

目前,我所瞭解到的websocket抓包工具備兩種:chrome的開發者模式中的Network,filder。有一篇文章寫的很棒,推薦一下:點我點我!

參考文檔

我只是個搬運工!!!

相關文章
相關標籤/搜索