1. 程式人生 > 其它 >go語言之websocket

go語言之websocket

1. 基礎概念

1.1 Websocket定義

WebSocket是一種應用層通訊協議,可在單個TCP連線上進行全雙工通訊。WebSocket協議在2011年由IETF標準化為RFC 6455,後由RFC 7936補充規範。Web IDL中的WebSocket API由W3C標準化。

WebSocket使得客戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向客戶端推送資料。在WebSocket API中,瀏覽器和伺服器只需要完成一次握手,兩者之間就可以建立永續性的連線,並進行雙向資料傳輸。

從上面概念上可以看出WebSocket的一些特點:應用層通訊協議、基於單個TCP連線、持久連線、全雙工雙向資料傳輸等。這些是比較粗泛的概念,任何一種協議的出現肯定有它的應用場景,下面就簡單介紹一下為什麼會出現WebSocket這一應用層通訊協議。

1.2 為什麼需要Websocket

客戶端跟伺服器之間的互動一般都是使用HTTP協議進行通訊的,相比較Websocket,HTTP最大的問題就是Http是個單工的協議,請求只能由客戶端發起,然後伺服器收到請求後處理並回傳資訊,伺服器不能主動向客戶端傳送資訊。對於一般的場景,HTTP是比較適用的,因為HTTP是一個單工的短連線協議,可以很好的節省連線維繫的成本,客戶端服務端完成一次互動後,就會斷開TCP連線,以便其它客戶端可以獲取連線,完成跟伺服器的互動。但是一旦出現類似於聊天這種場景,HTTP就不是很適用了,為了實現即時通訊,客戶端必須通過“輪詢”的方式,在特定的時間間隔內,由客戶端對伺服器發出 HTTP Request,伺服器在收到請求後,返回最新的資料給瀏覽器重新整理。可以想到,這種方式是有很多缺點的。

伺服器消耗資源大

為了應付客戶端的輪詢,HTTP連線必須不斷開啟關閉,或者一直保持開啟的狀態,即使伺服器的狀態沒有發生變化,客戶端資源也會一直被佔用,沒有辦法被釋放

效率低下

輪詢中獲得的有效資訊不可控,有可能一整天資料才發生一次變化,但是為了獲得這個變化,卻不得不一整天都在對伺服器進行輪詢,效率非常低

浪費頻寬資源

HTTP請求是包含著各種頭部資訊的,這就意味著,即使輪詢的請求裡面沒有任何資訊,一個HTTP也要有好幾百B的資料量,在高併發的狀況下進行輪詢,流量可能會非常龐大了,而且這些流量都是無用的

雖然比較新的輪詢技術,比如Comet。可以實現雙向通訊,但仍然需要反覆發出請求。而且在Comet中普遍採用的HTTP長連線也會消耗伺服器資源。基於這種情況,HTML5定義了WebSocket協議,能更好的節省伺服器資源和頻寬,並且能夠更實時地進行通訊。

1.3 WebSocket簡介

WebSocket是一種與HTTP不同的協議,兩者都位於OSI模型的應用層,並且都依賴於傳輸層的TCP協議。雖然它們不同,但RFC 6455規定:“WebSocket設計為通過80和443埠工作,以及支援HTTP代理和中介”,從而使其與HTTP協議相容。 為了實現相容性,WebSocket握手使用HTTP Upgrade頭從HTTP協議更改為WebSocket協議。

WebSocket協議支援Web瀏覽器(或其他客戶端應用程式)與Web伺服器之間的互動,具有較低的開銷,便於實現客戶端與伺服器的實時資料傳輸。 伺服器可以通過標準化的方式來實現,而無需客戶端首先請求內容,並允許訊息在保持連線開啟的同時來回傳遞。通過這種方式,可以在客戶端和伺服器之間進行雙向持續對話。 通訊通過TCP埠80或443完成,這在防火牆阻止非Web網路連線的環境下是有益的。

大多數瀏覽器都支援該協議,包括Google Chrome、Firefox、Safari、Microsoft Edge、Internet Explorer和Opera。

與HTTP不同,WebSocket提供全雙工通訊。此外,WebSocket還可以在TCP之上啟用訊息流。TCP單獨處理位元組流,沒有固有的訊息概念。 在WebSocket之前,使用Comet可以實現全雙工通訊。但是Comet存在TCP握手和HTTP頭的開銷,因此對於小訊息來說效率很低。WebSocket協議旨在解決這些問題。

WebSocket協議規範將ws(WebSocket)和wss(WebSocket Secure)定義為兩個新的統一資源識別符號(URI)方案,分別對應明文和加密連線。除了方案名稱和片段ID(不支援#)之外,其餘的URI元件都被定義為此URI的通用語法。使用瀏覽器開發人員工具,開發人員可以檢查WebSocket握手以及WebSocket框架。

1.4 WebSocket優點

較少的控制開銷。在連線建立後,伺服器和客戶端之間交換資料時,用於協議控制的資料包頭部相對較小。在不包含擴充套件的情況下,對於伺服器到客戶端的內容,此頭部大小隻有2至10位元組(和資料包長度有關);對於客戶端到伺服器的內容,此頭部還需要加上額外的4位元組的掩碼。相對於HTTP請求每次都要攜帶完整的頭部,此項開銷顯著減少了。
更強的實時性。由於協議是全雙工的,所以伺服器可以隨時主動給客戶端下發資料。相對於HTTP請求需要等待客戶端發起請求服務端才能響應,延遲明顯更少;即使是和Comet等類似的長輪詢比較,其也能在短時間內更多次地傳遞資料。
保持連線狀態。與HTTP不同的是,Websocket需要先建立連線,這就使得其成為一種有狀態的協議,之後通訊時可以省略部分狀態資訊。而HTTP請求可能需要在每個請求都攜帶狀態資訊(如身份認證等)。
更好的二進位制支援。Websocket定義了二進位制幀,相對HTTP,可以更輕鬆地處理二進位制內容。
可以支援擴充套件。Websocket定義了擴充套件,使用者可以擴充套件協議、實現部分自定義的子協議。如部分瀏覽器支援壓縮等。
更好的壓縮效果。相對於HTTP壓縮,Websocket在適當的擴充套件支援下,可以沿用之前內容的上下文,在傳遞類似的資料時,可以顯著地提高壓縮率。

1.5 WebSocket原理

WebSocket協議比較簡單,在第一次握手通過以後,連線便建立成功,其後的通訊資料都是以”\x00″開頭,以”\xFF”結尾。在客戶端,這個是透明的,WebSocket 元件會自動將原始資料 “掐頭去尾”。

瀏覽器發出WebSocket連線請求,然後伺服器發出迴應,然後連線建立成功,這個過程通常稱為 “握手” (handshaking)。請求和反饋資訊如下所示:

在請求中的”Sec-WebSocket-Key”是隨機的,對於整天跟編碼打交道的程式設計師,一眼就可以看出來:這個是一個經過base64編碼後的資料。伺服器端接收到這個請求之後需要把這個字串連線上一個固定的字串:

258EAFA5-E914-47DA-95CA-C5AB0DC85B11
即:f7cb4ezEAl6C3wRaU6JORA== 連線上那一串固定字串,生成一個這樣的字串:

f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
對該字串先用sha1安全雜湊演算法計算出二進位制的值,然後用base64對其進行編碼,即可以得到握手後的字串:

rE91AJhfC+6JdVcVXOGJEADEJdQ=
將之作為響應頭Sec-WebSocket-Accept的值反饋給客戶端。如此操作,可以儘量避免普通HTTP請求被誤認為Websocket協議。

本文來自部落格園,作者:zhanghuiyan,轉載請註明原文連結:https://www.cnblogs.com/zhanghuiyan/p/15149712.html