八股——WebSocket

文章目錄

  • 1、 什么是 WebSocket?與 Http 協議的區別是什么?
  • 2、 Http 是如何升級為 WebSocket 的?
  • 3、 為什么 WebSocket 可以進行全雙工模式的消息傳輸,而 Http 不可以?
  • 4、 什么是 TCP 的沾包和拆包?
  • 5、 WebSocket 與 Socket 套接字的區別是什么?
  • 6、 keep-alive 是什么?
  • 7、 網線被一腳踢斷了,TCP 連接會發生什么事情?
  • 8、SSE協議了解嗎?為什么用websocket而不用SSE?
  • 9、 Websocket如何保證消息可靠性?(重點強調不是安全性)


1、 什么是 WebSocket?與 Http 協議的區別是什么?

WebSocket 是一種應用層協議,用于在 Web 應用程序中創建實時、雙向的通信通道。傳統的 HTTP 請求通常是一次請求一次響應的,而 WebSocket 則可以建立一個持久連接,允許服務器即時向客戶端推送數據,同時也可以接收客戶端發送的數據。WebSocket 相比于傳統的輪詢或長輪詢方式,能夠顯著減少網絡流量和延遲,提高數據傳輸的效率和速度。
WebSocket 可以在瀏覽器和服務器之間建立一條雙向通信的通道,實現服務器主動向瀏覽器推送消息,而無需瀏覽器向服務器不斷發送請求。其原理是在瀏覽器和服務器之間建立一個“套接字”,通過“握手”的方式進行數據傳輸。由于該協議需要瀏覽器和服務器都支持,因此需要在應用程序中對其進行判斷和處理。
WebSocket 建立在 HTTP 協議之上,所有的 WebSocket 請求都會通過普通的 HTTP 協議發送出去,然后在服務器端根據 HTTP 協議識別特定的頭信息 Upgrade,服務端也會判斷請求信息中 Upgrade 是否存在。 這里面 HTTP 是必不可少的,不然 WebSocket 根本無法建立。特別的,WebSocket 在握手時采用了 Sec-WebSocket-Key 加密處理,并采用 SHA-1 (hash)簽名。
一旦建立了 WebSocket 連接,客戶端和服務器端就可以互相發送二進制流或 Unicode 字符串。所有的數據都是經過 mask 處理過的,mask 的值是由服務器端隨機生成的。在數據進行發送之前,必須先進行 mask 處理,這樣可以有效防止數據被第三方惡意篡改。
最后需要說明一下的是,WebSocket 的通信協議是基于幀(數據包)的。在數據發送時,一個完整的數據包可以分為多個幀進行發送(拆包/沾包),而每一個幀都包含了數據的一部分,同時還包含了幀頭信息。
[圖片]

[圖片]

WebSocket 與 Http 協議的區別

  1. HTTP (Hypertext Transfer Protocol) 是一個基于請求和響應模式的協議,最早用于 Web 應用。
  2. WebSocket 是一種雙向通信協議,可以在客戶端和服務器之間建立持久的連接,以實現實時通信。
  3. WebSocket 協議在建立連接時需要使用 HTTP 協議。 具體來說,當客戶端想要建立 WebSocket 連接時,它們需要通過 HTTP 請求發送一個握手請求。如果服務器同意握手,它將發送一個握手響應,HTTP 協議隨后會升級到 WebSocket 協議。
  4. HTTP 和 WebSocket 協議在用途上也有所不同。 HTTP 協議主要用于客戶端和服務器之間的請求和響應通信,而 WebSocket 協議主要用于實現實時通信和服務器推送。通俗的說,HTTP 協議是“一問一答”,WebSocket 協議是“對話”。

2、 Http 是如何升級為 WebSocket 的?

在這里插入圖片描述


3、 為什么 WebSocket 可以進行全雙工模式的消息傳輸,而 Http 不可以?

你可能會問,既然HTTP 與WebSocket 底層都是通過 TCP 進行消息傳輸的,為什么 Http 協議卻不能服務端主動給客戶端進行主動進行消息推送?其實這并不是 TCP 不支持全雙工的工作模式,HTTP的設計初衷是文檔傳輸,不是實時通信,所以沒有考慮持續的雙向通信需求。因此這是由于應用層協議設計的問題導致的 Http 協議不支持全雙工的工作模式。


4、 什么是 TCP 的沾包和拆包?

在回答這個問題之前我們需要明確沾包和拆包的定義是什么,如下

  • 粘包(Sticky Packets)
    發送方連續發送多個數據包時,接收方可能一次性收到多個包"粘"在一起的數據(如:發送 A|B,接收AB)。
  • 拆包(Unpacking)
    發送方的一個數據包可能被拆分成多次接收(如:發送 C,接收為 C1 和 C2)
    為什么會出現沾包和拆包這個問題呢?其根本原因是 TCP 面向的是字節流(字節流是你可以認為是一個一直在流水的水管)的協議,TCP 壓根就不知道你想發送的每個數據包之間的邊界是什么,那么如果你發送的一段信息過長,超過了 TCP 的緩沖區,那就會導致你的一個大的數據包被拆分為若干小的數據包進行發送,這就是拆包;當你的一個數據包過小,那么 TCP 會認為頻繁發送小數據包會頻繁進行網絡傳輸,因此會使用 Nagle 算法合并小數據包,這就是沾包。
    解決方案
    (1) 固定消息長度
  • 每個數據包長度固定(如1024字節),不足部分用空位填充。
  • 缺點:浪費帶寬,不靈活。
    (2) 分隔符協議
  • 用特殊字符(如\n、\r\n)標記消息邊界。
  • 示例:Redis協議使用\r\n分割命令。
    (3) 消息頭聲明長度
  • 在消息頭部添加長度字段(如4字節int),明確后續數據的長度。
  • 示例:HTTP協議通過Content-Length頭指定正文長度。

在本項目中 netty 框架已經幫我們在應用層方面解決了這個問題,Netty框架:內置解碼器如LengthFieldBasedFrameDecoder 自動處理粘包/拆包。


5、 WebSocket 與 Socket 套接字的區別是什么?

首先,Socket套接字,屬于傳輸層的API,像TCP和UDP都是基于Socket實現的。它允許應用程序通過網絡進行通信,是操作系統提供的接口。而WebSocket是一種應用層協議,建立在HTTP之上,提供全雙工通信,通常用于瀏覽器和服務器之間的實時交互。換句話說二者不屬于同一層面的東西。


6、 keep-alive 是什么?

TCP Keepalive機制 是一種用于檢測空閑連接是否存活的傳輸層保活策略。它通過定期發送探測報文,確認對端是否仍在線,避免因網絡中斷或對端崩潰導致連接長期占用資源。

  1. Keepalive 的工作原理
    (1) 觸發條件
  • 空閑超時:當連接在 tcp_keepalive_time 時間內無數據交互,觸發Keepalive探測。
  • 探測過程:發送空數據包(ACK標志,序列號為當前期望值減1),強制對端響應。
    (2) 探測流程
  • 發送探測包:每隔 tcp_keepalive_intvl 秒發送一次探測包。
  • 等待響應:若收到有效ACK,重置計時器,連接保持。
  • 失敗判定:連續 tcp_keepalive_probes 次無響應,判定連接死亡,發送RST斷開。
# 臨時生效(重啟后失效)
sysctl -w net.ipv4.tcp_keepalive_time=600    # 空閑10分鐘后探測
sysctl -w net.ipv4.tcp_keepalive_intvl=30    # 每隔30秒發送探測
sysctl -w net.ipv4.tcp_keepalive_probes=3    # 最多探測3次# 永久生效:將配置寫入 /etc/sysctl.conf
echo "net.ipv4.tcp_keepalive_time = 600" >> /etc/sysctl.conf
sysctl -p

7、 網線被一腳踢斷了,TCP 連接會發生什么事情?

首先,我們要回憶一下 TCP 的基礎知識,TCP 在會在什么情況下斷開一個鏈接呢?

  1. 連接雙方的一端主動進行 TCP 連接的關閉,就是我們常說的發送 FIN 包,進行四次揮手;
  2. 重傳次數達到閾值,TCP有重傳機制,如果多次重傳失敗,導致 TCP 連接斷開;
  3. Keepalive 機制如果啟用,在探測無響應后也會斷開連接;
  4. 接收到 RST 終止報文

    既然我們已經知道了 TCP 鏈接可能被關閉的情況,那么我們就可以對這個問題進行回答。首先分情況進行討論如果是網線被踢開了,那么我們軟件系統其實是無法馬上感知物理鏈路已經斷開了,TCP 連接狀態仍然ESTABLISHED狀態,此時如果你馬上把斷掉的網線插回去,那么其實 TCP 會當作什么都沒發生,因為他根本沒有感知到剛才的那次網線的斷開。如果你在網線斷開的時候,進行了消息的發送,那么由于物理網絡的斷開,那么你這條消息一定是發送不出去的,會觸發 TCP 的重傳機制,進行重傳,如果你在重傳時,將網線插回,那么這個 TCP 連接仍然不會斷開,因為重傳成功了,否則 TCP 連接將會被斷開。那么如果網線一直沒有被插回去,并且客戶端與服務端一直沒有通過這個 TCP 進行通信,那么這個 TCP 連接將會一直存在,那有沒有一個好的方法解決這個問題呢?答案是開啟Keepalive機制,Keepalive 機制簡單的說,就是定期的向 TCP 連接中發送探測數據包,來確保這條 TCP 連接是正常存活的,就像我們在 IM 項目的長鏈接模塊中,加入了心跳機制一樣。如果 Keepalive 探測數據包沒有得到響應,會幫我們自動關閉這條連接。

8、SSE協議了解嗎?為什么用websocket而不用SSE?

SSE是一種基于HTTP協議的服務器推送技術,允許服務器單向地向客戶端推送事件流數據。它的主要特點是:

  • 單向通信: 數據只能從服務器流向客戶端。
  • 基于HTTP: 無需新的協議,復用HTTP連接。
  • 文本協議: 主要傳輸UTF-8編碼的文本數據。
  • 自動重連: 瀏覽器標準中定義了斷線重連機制。
  • 實現相對簡單: 相比WebSocket,服務器端實現可能更簡單一些。

我們項目選擇WebSocket而不是SSE,主要是基于以下考慮:

  1. 核心需求是雙向通信: 我們的項目是一個即時通訊(IM)系統。用戶不僅需要接收來自服務器的消息推送(如新消息、在線狀態更新),還需要能夠實時地向服務器發送消息、發送已讀回執、發送正在輸入狀態等操作。WebSocket提供了全雙工通信能力,允許客戶端和服務器在建立連接后,隨時互相發送數據。而SSE是單向的,客戶端無法通過同一個SSE連接向服務器發送數據,如果需要客戶端發送,就必須發起新的HTTP請求,這違背了IM系統低延遲、高實時性的要求。
  2. 協議開銷和效率: 雖然WebSocket的握手階段比SSE復雜,但在連接建立后,其數據幀的協議開銷相對較小,尤其適合頻繁、小數據包的傳輸場景,這與IM的消息傳輸特性相符。如果使用SSE推送、HTTP發送,會增加額外的連接建立和請求開銷。
  3. 功能豐富性: WebSocket不僅支持文本數據,還原生支持二進制數據傳輸,這為未來可能擴展的功能(如傳輸圖片、文件、音視頻信令等)提供了更好的基礎。
    總結來說, 對于需要客戶端和服務端進行高頻實時雙向交互的IM應用場景,WebSocket的全雙工通信能力是其相比SSE最核心的優勢,也是我們選擇它的根本原因。SSE更適用于只需要服務器向客戶端單向推送信息的場景,例如股票行情更新、新聞推送等。

9、 Websocket如何保證消息可靠性?(重點強調不是安全性)

WebSocket協議本身是建立在TCP之上的,TCP協議提供了傳輸層的可靠性,包括數據包的順序保證和丟包重傳機制。但這并不等同于應用層消息的可靠性。比如,TCP連接可能意外斷開,或者服務器/客戶端在處理消息時崩潰,或者網絡長時間抖動導致TCP認為連接超時。因此,為了確保WebSocket上的應用層消息傳遞真正可靠(即消息不丟失、不重復、基本有序),我們在應用層(也就是在 Real-TimeCommunicationService 和客戶端之間)需要實現額外的機制:
1.消息確認機制 (ACK): 這是最核心的機制。

  • 發送方: 每發送一條需要保證可靠性的消息時,會附帶一個唯一的、單調遞增的消息ID(或序列號)。同時啟動一個定時器,等待接收方的確認應答(ACK)。
  • 接收方: 收到消息后,進行處理。處理成功后,向發送方回復一個ACK消息,其中包含收到的消息ID。
  • 超時與重傳: 如果發送方在定時器超時前沒有收到對應的ACK,就認為消息可能丟失,會進行重傳(可能需要設定最大重傳次數和退避策略)。
  1. 消息序列號 (Sequence Number): 為了保證消息的基本有序性(尤其是在重傳發生時),發送方可以為每個會話(或用戶連接)維護一個遞增的序列號。接收方可以根據序列號來判斷消息是否重復或失序。對于失序的消息,可以先緩存,等待前面的消息到達后再處理,或者直接丟棄(取決于業務要求)。
    3.** 冪等性保證**: 由于存在重傳機制,接收方可能會收到重復的消息。接收方需要具備冪等處理能力。通常可以通過檢查收到的消息ID是否已經被處理過來實現。例如,在Redis中記錄最近處理過的一批消息ID,或者在數據庫存儲消息時利用唯一ID約束。
  2. 心跳機制 (Heartbeat/Ping-Pong): 定期由客戶端或服務器(或雙方)發送心跳消息(Ping),對方收到后回復Pong。如果在一定時間內沒有收到對方的心跳響應,就認為連接已經失效。這有助于及早發現“假死”連接,觸發重連和后續的消息同步/重發邏輯。Netty本身提供了 IdleStateHandler 來方便地實現心跳檢測。
  3. 重連后的消息同步: 當連接斷開并重新建立后,客戶端需要與服務器同步狀態,拉取在離線期間可能錯過的消息。在我們的設計中,這部分主要是通過登錄時(包括重連后的自動登錄)與 OfflineDataStore 通過拉取離線消息來實現。對于重連前的“飛行中”消息(已發出但未確認ACK的),可以通過上述的ACK和序列號機制來決定是否需要重發。
    通過這些應用層的機制組合,我們在TCP提供的基礎傳輸可靠性之上,構建了更強的應用層消息可靠性保障,確保IM消息能夠盡可能地準確、完整、有序地送達。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92425.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92425.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92425.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mysql 如何使用 binlog 日志回滾操作失誤的數據

文章目錄一、背景二、準備測試數據1. 創建測試表2. 創建測試數據三、模擬誤操作四、數據回滾(一)方案一:云數據庫恢復(二)方案二:手動恢復1. 查詢 binlog 日志2. 找到刪除語句,手動還原為插入語…

wodpress結構化數據對SEO的作用

在 WordPress 網站中,結構化數據對 SEO 的作用主要體現在以下幾個方面: 1. 提升搜索結果的可見性 結構化數據能夠幫助搜索引擎更好地理解網頁內容,從而以更精準的方式展示搜索結果。通過添加結構化數據,網頁可以在搜索結果中顯示…

講一講@ImportResource

題目詳細答案ImportResource是 Spring 框架中的一個注解,用于將傳統的 XML 配置文件導入到基于 Java 配置的 Spring 應用程序中。它允許開發者在使用 Java 配置的同時,繼續利用現有的 XML 配置文件。這樣可以逐步遷移舊的 XML 配置,或者在某些…

解決 Nginx 反代中 proxy_ssl_name 環境變量失效問題:網頁能打開但登錄失敗

前言:在現代企業架構中,多域名反向代理是實現業務隔離、品牌獨立的常見方案。然而,看似簡單的Nginx配置背后,隱藏著與TLS協議、后端認證邏輯深度綁定的細節陷阱。本文將從原理到實踐,詳解為何在多域名場景下&#xff0…

三步完成,A100本地vLLM部署gpt-oss,并啟動遠程可訪問api

A100本地vLLM部署gpt-oss,并啟動遠程可訪問api GPT-oss試用 gpt-oss有兩個原生配置是目前(2025-8-8)Ampere系列顯卡不支持的,分別是默認的MXFP4量化,以及Flash-attn V3。官方給出的vllm教程也是默認使用的是H系列顯卡…

【華為機試】63. 不同路徑 II

文章目錄63. 不同路徑 II題目描述示例 1:示例 2:提示:解題思路核心思想:動態規劃(避開障礙)算法流程復雜度分析邊界與細節方法對比代碼實現Go 實現(含二維DP / 一維DP / 記憶化)測試…

C++ 模擬實現 map 和 set:掌握核心數據結構

C 模擬實現 map 和 set:掌握核心數據結構 文章目錄C 模擬實現 map 和 set:掌握核心數據結構一、set 和 map 的結構1.1 set的結構1.2 map的結構二、對紅黑樹的改造2.1 改造紅黑樹的節點2.2 改造紅黑樹2.2.1 仿函數的使用2.2.2 插入函數的改造2.2.3 刪除函…

根據ASTM D4169-23e1標準,如何選擇合適的流通周期進行測試?

根據ASTM D4169-23e1標準及行業實踐&#xff0c;選擇流通周期&#xff08;DC&#xff09;需綜合以下因素&#xff1a;一、核心選擇依據?產品屬性與包裝形式??重量體積?&#xff1a;輕小包裹&#xff08;<4.53kg且<0.056m&#xff09;適用DC2/3/4/6/9/13-17等周期&…

MySQL的觸發器:

目錄 觸發器的概念&#xff1a; 創建觸發器&#xff1a; 查看觸發器&#xff1a; 查看當前數據庫的所有觸發器的定義&#xff1a; 查看當前數據中某個觸發器的定義&#xff1a; 從系統information_schema的TRIGGERS表中查詢"salary_check_trigger"觸發器的信息…

基于ubuntu搭建gitlab

原文地址&#xff1a;基于ubuntu搭建gitlab – 無敵牛 歡迎參觀我的網站&#xff1a;無敵牛 – 技術/著作/典籍/分享等 之前介紹了一個使用 git openssh-server 搭建一個極簡 git 庫的方法&#xff0c;感興趣可以查看往期文章&#xff1a;手搓一個極簡遠端git庫 – 無敵牛 。…

測試GO前沿實驗室:為水系電池研究提供多維度表征解決方案

測試GO前沿實驗室&#xff1a;為水系電池研究提供多維度表征解決方案隨著全球能源轉型加速&#xff0c;水系電池因其高安全性、低成本和環境友好特性&#xff0c;成為下一代儲能技術的重要發展方向。測試狗前沿實驗室針對水系電池研發中的關鍵科學問題&#xff0c;整合先進表征…

Spring Boot 中 YAML 配置文件詳解

Spring Boot 中 YAML 配置文件詳解 在 Spring Boot 項目中&#xff0c;配置文件是不可或缺的一部分&#xff0c;用于自定義應用行為、覆蓋默認設置。除了傳統的 properties 文件&#xff0c;Spring Boot 對 YAML&#xff08;YAML Ain’t Markup Language&#xff09;格式提供了…

Milvus安裝可視化工具,attu,保姆級

安裝包鏈接&#xff1a;GitHub - zilliztech/attu: Web UI for Milvus Vector Databasehttps://github.com/zilliztech/attu?tabreadme-ov-file 下滑 舉例&#xff1a;windows&#xff1a;下載安裝&#xff0c;然后就可以連接了&#xff08;安裝完打開后如果需要輸入用戶名密碼…

避免“卡脖子”!如何減少內存I/O延遲對程序的影響?

單來說&#xff0c;內存 IO 就像是計算機的 “數據高速公路”&#xff0c;負責在內存和其他設備&#xff08;如硬盤、CPU 等&#xff09;之間傳輸數據。它的速度和效率直接影響著計算機系統的整體性能。 你有沒有想過&#xff0c;當你點擊電腦上的一個應用程序&#xff0c;它是…

V4L2攝像頭采集 + WiFi實時傳輸實戰全流程

&#x1f4d6; 推薦閱讀&#xff1a;《Yocto項目實戰教程:高效定制嵌入式Linux系統》 &#x1f3a5; 更多學習視頻請關注 B 站&#xff1a;嵌入式Jerry V4L2攝像頭采集 WiFi實時傳輸實戰全流程 1. 實戰場景概述 目標&#xff1a; 嵌入式設備&#xff08;如RK3588/正點原子開發…

Java 之 設計模式

1.單例模式1. ??餓漢式&#xff08;Eager Initialization&#xff09;????核心原理??&#xff1a;類加載時立即創建實例&#xff0c;通過靜態變量直接初始化。??代碼示例??&#xff1a;public class Singleton {private static final Singleton INSTANCE new Sing…

[激光原理與應用-185]:光學器件 - BBO、LBO、CLBO晶體的全面比較

一、相同點非線性光學晶體屬性BBO、LBO、CLBO均為非中心對稱晶體&#xff0c;具備非線性光學效應&#xff0c;廣泛應用于激光頻率轉換&#xff08;如倍頻、三倍頻、和頻、差頻&#xff09;、光學參量振蕩&#xff08;OPO&#xff09;及電光調制等領域。寬透光范圍三者均覆蓋紫外…

Android APN加載耗時優化可行性分析

背景 根據Android系統底層機制和行業實踐,本文討論 APN 加載耗時從4.2s降至0.8s的數據合理性和技術可行性,需結合具體優化手段和硬件環境綜合分析。 以下是關鍵判斷依據及行業參考: ?? 一、APN加載耗時基準參考 未優化場景的典型耗時 首次開機或重置后:APN需從apns-con…

mysql進階-sql調優

概述優化索引在MySQL初階的課程中已經介紹了索引&#xff0c;我們知道InnoDB存儲引擎使?B樹作為索引默認的數據結構來組織數據&#xff0c;為頻繁查詢的列建?索引可以有效的提升查詢效率&#xff0c;那么如何利?索引編寫出?效的SQL查詢語句&#xff1f;以及如何分析某個查詢…

海量數據處理問題詳解

1.從a&#xff0c;b兩個文件各存放50億個url&#xff08;每個url大小為64B&#xff09;&#xff0c;如何在內存為4G中查找a&#xff0c;b中相同的url 計算各文件存放大小&#xff1a;50億*64B 大約為320G&#xff0c;而內存只有4G&#xff0c;顯然存放不下&#xff0c;此時我們…