淺析WebSocket(1)

来源:https://www.cnblogs.com/vanter-sloe/archive/2022/06/27/16402131.html
-Advertisement-
Play Games

簡介 WebSocket 是雙工的,他支持在客戶端和伺服器之間互相發送文本或二進位消息流,除此功能以外,它還提供了更為複雜的附加擴展: 連接協商和同源策略實施 與現有HTTP基礎設施的互相操作性 面向消息的通信和高效的消息框架 這一點與Socket不同,Socket算是面向位元組,他沒有消息頭、消息尾 ...


簡介

WebSocket 是雙工的,他支持在客戶端和伺服器之間互相發送文本或二進位消息流,除此功能以外,它還提供了更為複雜的附加擴展:

  • 連接協商和同源策略實施

  • 與現有HTTP基礎設施的互相操作性

  • 面向消息的通信和高效的消息框架

    這一點與Socket不同,Socket算是面向位元組,他沒有消息頭、消息尾的概念。可以說Socket沒有那麼聰明

  • 子協議協商和可擴展性

值得註意的一點是:WebSocket 不是 HTTP、XHR 或 SSE 的替代品,為了獲得最佳性能,利用每種傳輸的優勢至關重要。

WS 和 WSS URL 方案

這兩種方案都是WebSocket的自定義方案,WS用於純文本(即:明文)通訊,WSS用於加密管道通訊。

文本消息和二進位消息

WebSocket比較好的一點就是:無需擔心緩衝、解析和重構接收到的數據。

例:如果伺服器發送 1 MB 的有效負載,客戶端每次只能接收250 kb的有效荷載,那麼他會接收四次,當接收完畢後onmessage才會在客戶端調用應用程式的回調。

有效負載:我有個長度為5 MB的位元組容器(即:一個int類型的數組),我要發送的消息轉為位元組數組後,長度只有1 MB,那麼這1 MB稱為有效負載,剩下的將是無效負載

有效載荷:客戶端每次只能接收250 kb(即:一個長度為250*1024的位元組數組),如果接收到了200 kb的數據,那麼200有效載荷 50無效載荷

性能

瀏覽器接收到一條新消息時,它會自動轉換為基於文本數據的 DOMString 對象或二進位數據的 Blob 對象,作為客戶端性能提升和優化的唯一方法就是,告訴瀏覽器將收到的二進位數據轉換為ArrayBuffer 而不是Blob

var ws = new WebSocket('wss://example.com/socket'); 
ws.binaryType = "arraybuffer";

Blob:離線存在磁碟中或單獨存在記憶體中

Blob 對象表示不可變的原始數據的類文件對象,如果您不需要改動二進位數據(例如我只需要這麼一個Blob文件對象),那麼這是最好的選擇。

ArrayBuffer:可能更有效將數據保存在記憶體中

如果您需要對二進位數據進行額外的處理,那麼ArrayBuffer可能更合適。

ArrayBuffer 是一個結構化的,二進位數據的固定長度容器

關於發送文本和二進位數據

WebSocket 連接成功後,客戶端將是一個雙向通訊管道,它允許通過同一個 TCP 連接在兩個方向上傳遞消息,發送或接收 UTF-8 和二進位消息。

預設Send方法,接受一個 DOMString 對象,該對象線上路上被編碼為 UTF-8,當然也可以用於二進位傳輸的 ArrayBuffer、ArrayBufferView 或 Blob 對象之一。

但是請註意,後一種二進位的方式只是為了方便API,在網路層面中,WebSocket的數據幀(即:發送的數據包),會通過單個位元組位標記為二進位或文本,因此,如果應用程式想要使用其他類型的信息,那麼雙方必須約定一種新的機制來通訊該數據。

關於Send方法

Send方法是非同步的,將提供的數據由客戶端排隊發出,立即返回結果,這裡的立即返回結果不代表你的信息已經發送完了,真正的發送完成是要監控當前瀏覽器的排隊數據量

var ws = new WebSocket('wss://example.com/socket');
ws.onopen = function () {
  // 當應用更新時觸發
  subscribeToApplicationUpdates(function(evt) {
    // 如果待發送的位元組數為0
    if (ws.bufferedAmount == 0)
      // 發送下一次請求
      ws.send(evt.data);
  });
};

所有 WebSocket 消息都按照它們在客戶端排隊的確切順序進行傳遞!!!

大量的排隊消息,或者單個大消息都將延遲其後面排隊的消息的傳遞——隊列頭阻塞!

解決方案:

  • 大消息拆分成更小的塊
  • 實現自己的優先順序隊列

應用程式應該密切關註每種類型的消息如何以及何時在套接字上排隊!

子協議協商

WebSocket 協議的預設消息格式只有兩種,文本數據和二進位數據,以便客戶端和服務端可以有效的對其進行編碼,如果不屬於這兩種,消息內容將是不透明的,服務端和客戶端將會不認識,導致無法解釋其內容。

WebSocket 與 HTTP 或 XHR請求不同,它們通過Header傳遞額外的信息,而WebSocket沒有這樣的協議,因此如果想要獲取額外的數據信息,那麼可以通過下麵的方式:

  • 統一的JSON編碼或自定義的二進位數據來通訊

  • 如果想要傳輸不同格式的數據,那麼可以通過約定消息頭

  • 文本和二進位消息混合使用

原始的WebSocket提供了子協議協商API來解決這個問題,最開始連接時,客戶端可以告訴伺服器他支持的協議,例:

var ws = new WebSocket('wss://example.com/socket', 
                       ['appProtocol', 'appProtocol-v2'])

如果子協議協商成功,則在 onopen處觸發回調,應用程式可以查詢WebSocket實例上的protocol屬性來確定伺服器選擇的協議,如果協商不成功,即伺服器不支持,則代表WebSocket協商是不完整的,將調用onerror回調。

WebSocket的協議

WebSocket協議由兩個高級組件組成:

  • 用於協商連接參數的開放 HTTP 握手
  • 一種二進位消息框架機制,允許文本和二進位數據的低開銷、基於消息的交付

WebSocket 協議是一個功能齊全的獨立協議,可以在瀏覽器之外使用。話雖如此,它的主要應用程式是作為基於瀏覽器的應用程式的雙向傳輸。

二進位框架層

WebSocket 使用了一種自定義的二進位幀格式,它將每個應用程式消息拆分為一個或多個,將它們傳輸到目的地,重新組裝它們,最後在收到整個消息後通知接收者。

  • 通信的最小單元,每一單元包含一個變長幀報頭和一個可以承載全部或部分應用程式消息的有效載荷。

  • 消息

    映射到邏輯應用程式消息的一個完整的幀序列。

我們瞭解一下WebSocket的是怎麼運行的?

我們先來看一下幀的內容:

幀是一個32位數據包(即:32-bit,一次處理4位元組,1位元組8位),我們來由淺入深一下:

比如a在ASCII編碼中代表著97,那麼97也就是所謂的位元組,然後再通過toString(2)得到01100001,這是一個8 bit(即:8位)的位數據,所謂的就是這樣的一堆二進位(也就是前面提到的8 bit)組成的。

現在我們來看一下伺服器發送給客戶端的原始數據,伺服器發送給客戶端的信息是兩個簡單的字元:aa

10000001 00000010 01100001 01100001

這是四位元組,你可以嘗試用後兩個位元組 01100001 01100001 去二進位轉換字元串(但是在轉換時您需要將它拼接起來,0110000101100001),你將得到信息aa

那麼前面兩個位元組中包含著什麼呢?

只是在目前的例子中他是占用了兩個位元組,其他情況下請參考數據內容

我們來看第一個位元組(10000001)

  • 1

    FIN:表示該數據包是不是消息的最後一個數據包(也就是說,如果他不是1,那麼表示數據包還沒有傳輸完成)

  • 000,分別代表RSV1、RSV2、RSV3,

    這三位必須是0,除非與伺服器協商了該擴展,如果這三個都不為0,那麼伺服器應該立即終止鏈接

  • 0001

    這四位代表操作碼

    • 0000:代表連續的幀
    • 0001:代表文本幀
    • 0010:代表二進位幀
    • 0011-0111:保留的幀,一般碰不到
    • 1000:代表連接要關閉
    • 1001:表示ping
    • 1010:表示pong
    • 1011-1111:保留的幀

我們接下來拆分第二個位元組(00000010)

  • 0

    掩碼,如果該位為1,那麼後面會有一個掩碼秘鑰,秘鑰占4位元組

  • 0000010

    這七位代表有效的載荷長度,轉換為數字為:2,也就是對應的aa的長度,在這裡如果轉換為的數字為0-125,那麼這就是應用數據的有效載荷長度。

    如果為126,那麼應該加上往後的擴展載荷長度,此情況下,擴展載荷長度為2個位元組。

    如果為127,那麼擴展載荷長度為8個位元組。

    如果有擴展的長度,那麼就需要將這些長度的位拼接起來,轉換為一個數字,該數字為真正的有效載荷的長度。

向後可能會出現的所屬於框架的位元組

  • 0或4位元組

    該項為掩碼秘鑰,用於屏蔽有效負載數據,即加密,此加密在本文下方有解釋。

  • 有效載荷數據:X+Y

    即擴展數據加應用數據

  • 擴展數據

    該數據應該是在創建連接(即:握手時)就應該協商好的,預設為0位元組,除非協商了擴展,以及定義好了擴展的長度,或長度應該如何計算。

  • 應用數據

    在擴展數據後的幀將是應用數據

掩碼、中介執行緩存中毒攻擊

掩碼是為了防止中介執行緩存中毒攻擊,該攻擊方式重點在於中介,此處的中介也就是一個代理伺服器,假設他是一個負載均衡代理,那麼他將負責轉發流量,我們知道WebSocket和HTTP並不相同,WebSocket發送到是原始位元組,這可以使其發送任何內容,比如模仿一個http請求:

soc.send(`
GET /script.js HTTP/1.1
HOST:惡意站點
`)

當這樣的一個消息,發送至中介伺服器時,中介伺服器並不知道這是一個WebSocket的數據封包,它將會被認為是HTTP請求,這將轉發到惡意站點,此時如果有相應的緩存設置,那麼接下來,訪問該安全站點 script.js 文件的無辜用戶,將會獲取到惡意站點的 script.js 文件。

而掩碼將會將 WebSocket 發送出去的數據進行屏蔽(加密),屏蔽完的數據他將不是明文的,而是看上去像是亂碼的數據。

至此,WebSocket的基本原理就是這樣,以上全文均為本人個人理解,如果有誤還請各位dai佬們指出。

接下來我會抽空將C#編寫的簡易WebSocketClient做成博客發出來。

第一次發博客,輕點噴,在此求求各位大佬了~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Android系統日誌 我們經常需要查看設備裡面的各種日誌信息。所以有必要瞭解android系統裡面有哪些日誌,以及用什麼方式可以提取這些日誌。以我手頭的紅米note4xplus為例,其基本配置為高通msm8953,android7.0。我們可以看一下根文件系統: mido:/ # ls acct ...
  • 從全民娛樂到全民創作,音視頻、直播已成為文娛市場中最為活躍的內容形態,用戶在享受視聽娛樂的同時,也更期待通過這些平臺來表達自己。 面對用戶個性化需求的增加,影音娛樂應用開發者和內容平臺,該如何通過技術手段創新產品功能,提升用戶體驗,讓應用搶占用戶興趣“高地”? 6月28日,HDD-HMS Core. ...
  • 【layui2.6.8】有多個文件上傳的組件需要根據後臺數據在頁面載入時動態渲染在一個彈框裡面。彈窗從table表格數據的【編輯】按鈕打開,根據點擊行展示不同的文件,對文件進行查詢、刪除、下載等管理。問題:選擇文件,不上傳,關閉彈窗再打開,剛選的文件雖然不見了,但依然能上傳那個文件,需要打開彈窗時清 ...
  • 📰前言 這個小項目源於github項目:✨50 projects 50 days, 這個項目包含了50個小型前端項目,適合學習了Html+Css+JavaScript但是還沒有學習框架的前端新手作為練習。 這裡是原項目對模糊載入的代碼實現👉Blurry Loading. 📋分析 變化過程: 數 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 對vue項目來說,組件是構成項目的基本單元,為了方便理解,這裡定義兩類組件:頁面組件,功能組件。為什麼需要劃分這兩類組件是從組件復用來考慮的。 我們知道在複雜應用中,頁面狀態管理早已不是早期的簡單的子父組件的傳值,兄弟組件傳值。而當我們尋 ...
  • 自此整個項目前後臺,全部搭建完畢。 今天是最後一天,內容很多,而且也比較常用,一個圖標類數據可視化,一個後臺的許可權管理,都是很經典的類型。 一.數據可視化 1.簡介 專門的一門學科,有專門研究這個的崗位,將數據以各種圖形進行展示 Echarts只能2D,three.js可開發3D 2.canvas繪 ...
  • 什麼是單文件組件? 簡言之,單文件組件就是一個文件擴展名為.vue的single-file-components(SFC)。是Vue.js自定義的一種文件格式,一個.vue文件,就是一個單獨的組件,在文件內封裝了組件的相關代碼:HTML,CSS,JS。 瀏覽器本身並不支持.vue文件,所以必須對.v ...
  • 巨集任務和微任務的隊列入門知識,可以參考之前的文章: JavaScript的事件迴圈機制 巨集任務和微任務在前端面試中,被經常提及到,包括口頭和筆試題 async && await概念 async 使用async關鍵字聲明的函數,是AsyncFunction構造函數的實例,在async函數體內,可以使用 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...