TCP為什么是三次握手,而不是二次?

為什么需要三次握手?

想象一下,你要給遠方的朋友寄一份重要文件。你會怎么做?

普通人的做法: 直接扔進郵箱,祈禱別丟了
聰明人的做法: 先打電話確認地址,再發快遞,最后確認收到

TCP的三次握手就是"聰明人的做法"。在茫茫網絡中,兩臺計算機要建立可靠連接,必須先"對暗號",確保雙方都準備好了,才能開始傳輸重要數據。

什么是三次握手?

三次握手(Three-Way Handshake) 是TCP協議建立連接的標準流程,就像兩個人見面前的三句對話:

  1. 第一次握手: “你好,我是小明,能聽到嗎?”
  2. 第二次握手: “聽到了,我是小紅,你能聽到我嗎?”
  3. 第三次握手: “能聽到,咱們開始聊吧!”

這三步走完,雙方就確認了:

  • 我能發消息給你 ?
  • 你能發消息給我 ?
  • 我們都準備好了 ?

生活中隨處可見的握手

瀏覽器訪問網站

當你在瀏覽器輸入 www.bd.com 時:

你的瀏覽器 → 百度服務器:"我想訪問你的網站"
百度服務器 → 你的瀏覽器:"可以,我準備好了,你準備好了嗎?"
你的瀏覽器 → 百度服務器:"我也準備好了,開始傳輸網頁吧!"

手機App聯網

打開微信、抖音等App時,底層都在進行三次握手:

  • App客戶端發起連接請求
  • 服務器確認并詢問客戶端狀態
  • 客戶端確認,開始數據傳輸

在線游戲連接

玩王者榮耀時的"正在連接服務器",實際上就是三次握手在工作!

深入理解握手機制

核心流程圖解

在這里插入圖片描述

關鍵參數解析

SYN (Synchronize):同步標志位

  • SYN=1 表示這是一個連接請求或連接確認報文

ACK (Acknowledgment):確認標志位

  • ACK=1 表示確認號字段有效

seq(序列號):數據包的序號

  • 用于保證數據傳輸的順序性

ack(確認號):期望收到的下一個數據包序號

  • ack = 收到的seq + 1

狀態變遷詳解

客戶端狀態變化:
CLOSED → SYN_SENT → ESTABLISHED服務端狀態變化:  
CLOSED → LISTEN → SYN_RECEIVED → ESTABLISHED

擴展篇:深度思考

為什么是三次,不是兩次或四次?

兩次握手的問題:

場景:網絡延遲導致的重復連接請求1. 客戶端發送連接請求A(因網絡問題延遲)
2. 客戶端以為失敗,重新發送請求B
3. 服務端先收到B,建立連接,正常通信后關閉
4. 延遲的請求A到達,服務端又建立連接
5. 但客戶端已經不需要了,造成資源浪費!

三次握手解決方案:
第三次握手讓客戶端確認這是自己想要的連接,避免了舊連接請求造成的問題。

四次握手: 沒必要,三次已經足夠確認雙方通信能力。

三次握手的安全漏洞

SYN洪水攻擊(SYN Flood):

// 攻擊原理模擬(僅用于理解,切勿用于實際攻擊)
for(int i = 0; i < 10000; i++) {// 發送大量SYN請求,使用虛假IPsendSynPacket(targetServer, fakeIP);// 服務器等待第三次握手,資源被耗盡
}

防護措施:

  • SYN Cookie技術
  • 連接超時機制
  • 防火墻過濾

代碼實現:模擬三次握手

Java Socket實現

客戶端代碼:

public class TCPClient {public static void main(String[] args) {try {// 創建Socket,這里會自動進行三次握手Socket socket = new Socket("127.0.0.1", 8080);System.out.println("🤝 三次握手完成,連接建立!");// 發送數據PrintWriter out = new PrintWriter(socket.getOutputStream(), true);out.println("Hello Server!");// 接收響應BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));String response = in.readLine();System.out.println("服務器響應:" + response);socket.close();} catch (IOException e) {System.err.println("連接失敗:" + e.getMessage());}}
}

服務端代碼:

public class TCPServer {public static void main(String[] args) {try {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("🚀 服務器啟動,等待連接...");while (true) {// accept()方法會完成三次握手的服務端部分Socket clientSocket = serverSocket.accept();System.out.println("🤝 新客戶端連接建立!");// 處理客戶端請求handleClient(clientSocket);}} catch (IOException e) {System.err.println("服務器錯誤:" + e.getMessage());}}private static void handleClient(Socket socket) {try {BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out = new PrintWriter(socket.getOutputStream(), true);String message = in.readLine();System.out.println("收到消息:" + message);out.println("Hello Client! 消息已收到");socket.close();} catch (IOException e) {System.err.println("處理客戶端錯誤:" + e.getMessage());}}
}

底層原理模擬

// 模擬TCP三次握手的核心邏輯
public class HandshakeSimulator {static class TCPPacket {boolean SYN;boolean ACK;  int seq;int ack;public TCPPacket(boolean syn, boolean ackFlag, int seqNum, int ackNum) {this.SYN = syn;this.ACK = ackFlag;this.seq = seqNum;this.ack = ackNum;}@Overridepublic String toString() {return String.format("SYN=%s, ACK=%s, seq=%d, ack=%d", SYN, ACK, seq, ack);}}public static void main(String[] args) {Random random = new Random();int clientSeq = random.nextInt(1000);int serverSeq = random.nextInt(1000);System.out.println("🌟 TCP三次握手模擬開始");System.out.println("=" * 50);// 第一次握手:客戶端發送SYNTCPPacket syn = new TCPPacket(true, false, clientSeq, 0);System.out.println("👤 客戶端 → 服務端:" + syn);System.out.println("   含義:我想建立連接,我的初始序號是 " + clientSeq);// 第二次握手:服務端響應SYN+ACKTCPPacket synAck = new TCPPacket(true, true, serverSeq, clientSeq + 1);System.out.println("🔄 服務端 → 客戶端:" + synAck);System.out.println("   含義:收到了,我同意連接,我的序號是 " + serverSeq + ",期待你的序號 " + (clientSeq + 1));// 第三次握手:客戶端發送ACKTCPPacket ack = new TCPPacket(false, true, clientSeq + 1, serverSeq + 1);System.out.println("? 客戶端 → 服務端:" + ack);System.out.println("   含義:收到確認,連接建立成功!");System.out.println("=" * 50);System.out.println("🎉 三次握手完成,開始數據傳輸!");}
}

面試熱點:高頻問題全解析

Q1: 為什么TCP需要三次握手?

標準答案:
確保雙方的發送和接收能力都正常:

  • 第一次:確認客戶端發送能力、服務端接收能力
  • 第二次:確認服務端發送能力、客戶端接收能力
  • 第三次:確認客戶端接收到服務端的確認

加分回答:
防止舊的重復連接請求突然又傳送到服務端,避免產生錯誤連接。

Q2: 三次握手過程中丟包怎么辦?

第一次握手丟包: 客戶端超時重傳SYN
第二次握手丟包: 客戶端重傳SYN,服務端重傳SYN+ACK
第三次握手丟包: 服務端重傳SYN+ACK,客戶端重傳ACK

Q3: 能否設計成兩次握手?

不能! 兩次握手無法確認客戶端的接收能力,會導致:

  1. 服務端無法確認客戶端是否收到連接確認
  2. 可能建立無效連接,浪費服務端資源
  3. 無法防范延遲連接請求的問題

Q4: SYN攻擊的原理和防護?

攻擊原理:

攻擊者發送大量SYN請求 → 服務端維護大量半連接 → 
資源耗盡 → 無法處理正常請求

防護策略:

  • SYN Cookie: 不保存連接狀態,通過算法驗證
  • 超時機制: 快速清理無效連接
  • 連接限制: 限制單IP連接數

Q5: 握手過程中的序列號有什么作用?

核心作用:

  1. 防重放攻擊: 每次連接使用不同的初始序號
  2. 保證順序: 確保數據包按正確順序組裝
  3. 可靠傳輸: 配合確認號實現重傳機制

實戰應用:優化連接性能

連接池優化

// 使用連接池避免頻繁握手
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(20);  // 維護20個連接
config.setMinimumIdle(5);       // 最少保持5個空閑連接
HikariDataSource dataSource = new HikariDataSource(config);// 這樣就避免了每次數據庫操作都要三次握手

Keep-Alive機制

// HTTP Keep-Alive復用TCP連接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Connection", "keep-alive");
// 一次握手,多次請求!

總結

三次握手雖然看起來簡單,但它是網絡通信可靠性的基石。掌握了三次握手,你就理解了:

🔹 為什么網絡連接需要時間 - 握手需要時間
🔹 為什么有些攻擊很危險 - SYN洪水攻擊原理
🔹 為什么要使用連接池 - 避免頻繁握手開銷
🔹 為什么網絡編程要考慮異常 - 握手可能失敗

記住這個比喻,三次握手就像兩個人見面前的確認過程,確保雙方都準備好了再開始重要的交流。簡單、有效、不可缺少!

下次面試官問起三次握手,你就可以從原理講到應用,從安全講到優化,展現你的深度思考能力! 🚀

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

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

相關文章

dubbo使用nacos作為注冊中心配置

<dubbo:registry protocol"nacos" address"${dubbo.registry.address.nacos}" /> <dubbo:metadata-report address"${dubbo.metadata-report.address}"/> 如果有多個地址&#xff0c;這塊如何配置呢&#xff1f; nacos://ip:端口?…

教師角色的轉變:從知識傳授者到學習引導者

教師角色的轉變&#xff1a;從知識傳授者到學習引導者 隨著人工智能&#xff08;AI&#xff09;和信息技術的迅速發展&#xff0c;教育正在經歷深刻的變革。其中&#xff0c;教師角色的轉變尤為關鍵。傳統上&#xff0c;教師主要承擔“知識傳授者”的職責&#xff0c;即向學生…

PostgreSQL 用戶權限與安全管理

1 系統默認角色 postgres# select rolname from pg_roles; rolname ----------------------------- postgres pg_database_owner pg_read_all_data pg_write_all_data pg_monitor pg_read_all_settings pg_read_all_stats pg_stat_scan_tables …

C++構造函數和析構函數

C++構造函數和析構函數 C++的構造函數和析構函數是類的特殊成員函數,用于對象的創建和銷毀,分別在對象的生命周期開始和結束時自動調用。它們的使用對資源管理和對象的初始化/清理至關重要。 1. 構造函數 定義 構造函數在對象創建時自動調用,用于初始化對象的數據成員。構造…

根據Cortex-M3(STM32F1)權威指南講解MCU內存架構與如何查看編譯器生成的地址具體位置

首先我們先查看官方對于Cortex-M3預定義的存儲器映射 1.存儲器映射 1.1 Cortex-M3架構的存儲器結構 內部私有外設總線&#xff1a;即AHB總線&#xff0c;包括NVIC中斷&#xff0c;ITM硬件調試&#xff0c;FPB, DWT。 外部私有外設總線&#xff1a;即APB總線&#xff0c;用于…

軟件設計師“測試用例”考點分析——求三連

一、測試用例設計核心要點解析 1. 白盒測試覆蓋標準 &#xff08;1&#xff09;路徑覆蓋&#xff1a;需覆蓋程序中所有可能的路徑。如2018年真題路徑覆蓋需要3組測試用例&#xff08;①②、①③、①③④&#xff09;&#xff0c;2020年流程圖則需4個用例覆蓋ace/abd/abe/acd四…

Linux 用戶無法遠程連接服務器

前言 昨天深夜一點多接到客戶電話&#xff0c;客戶說OS用戶下午下班前還能正常登錄。因為晚上一點半需要關閉所有服務進行遷移&#xff0c;但是用戶無法登錄了&#xff0c;導致后續流程無法執行。我讓他先通過root用戶緊急修改了密碼&#xff0c;先保證業務正常流轉。 問題 …

多模態大語言模型arxiv論文略讀(八十八)

MammothModa: Multi-Modal Large Language Model ?? 論文標題&#xff1a;MammothModa: Multi-Modal Large Language Model ?? 論文作者&#xff1a;Qi She, Junwen Pan, Xin Wan, Rui Zhang, Dawei Lu, Kai Huang ?? 研究機構: ByteDance, Beijing, China ?? 問題背景…

svn遷移到git保留記錄和Python字符串格式化 f-string的進化歷程

svn遷移到git保留記錄 and Python字符串格式化(二&#xff09;&#xff1a; f-string的進化歷程 在將項目從SVN遷移到Git時&#xff0c;保留完整的版本歷史記錄非常重要。下面是詳細的步驟和工具&#xff0c;可以幫助你完成這一過程&#xff1a; 安裝Git和SVN工具 首先&#…

springboot配置mysql druid連接池,以及連接池參數解釋

文章目錄 前置配置方式參數解釋 前置 springboot 項目javamysqldruid 連接池 配置方式 在 springboot 的 application.yml 中配置基本方式 # Druid 配置&#xff08;Spring Boot YAML 格式&#xff09; spring:datasource:url: jdbc:mysql://localhost:3306/testdb?useSSL…

vue實現高亮文字效果——advanced-mark.js

組件介紹-advanced-mark.js&#xff1a; advanced-mark.js 是一個用于 Vue 的高亮文字組件&#xff0c;它可以幫助你在文本中高亮顯示指定的關鍵詞或短語。 組件地址&#xff1a;https://angezid.github.io/advanced-mark.js/doc-v2/getting-started.html 主要功能&#xff1…

DC30V/2.5A同步降壓芯片SL1581 輸入24V降壓5V 12V2A電流

在工業自動化、汽車電子等領域&#xff0c;24V 電源系統向 5V/12V 雙軌供電的需求日益增長。針對這一痛點&#xff0c;森利威爾電子重磅推出 DC30V/2.5A 同步降壓芯片 SL1581&#xff0c;憑借卓越的性能和創新設計&#xff0c;為工程師提供高可靠性、高性價比的電源解決方案。 …

React 第四十四節Router中 usefetcher的使用詳解及注意事項

前言 useFetcher 是 React Router 中一個強大的鉤子&#xff0c;用于在不觸發頁面導航的情況下執行數據加載&#xff08;GET&#xff09;或提交&#xff08;POST&#xff09;。 一、useFetcher 應用場景&#xff1a; 1、后臺數據預加載&#xff08;如鼠標懸停時加載數據&…

Jmeter(三) - 測試計劃(Test Plan)的元件

1.簡介 上一篇已經教你如何通過JMeter來創建一個測試計劃&#xff08;Test Plan&#xff09;&#xff0c;那么這一篇我們就將JMeter啟動起來&#xff0c;創建一個測試計劃&#xff08;Test plan&#xff09;&#xff0c;給大家介紹一下測試計劃&#xff08;Test Plan&#xff…

應屆本科生簡歷制作指南

一、找一個專業的簡歷模板 首先&#xff0c;你需要訪問 Overleaf 的官方網站&#xff0c;也就是Overleaf, Online LaTeX Editor&#xff0c;進入頁面后&#xff0c;點擊注冊按鈕&#xff0c;按照提示填寫相關信息來創建一個屬于自己的賬號&#xff0c;通常需要填寫用戶名、郵箱…

[Spring Boot]整合Java Mail實現Outlook發送郵件

日常開發過程中,我們經常需要使用到郵件發送任務,比方說驗證碼的發送、日常信息的通知等。日常比較常用的郵件發送方包括:163、QQ等,本文主要講解Outlook SMTP的開啟方式、OutLook STARTTTL的配置、如何通過JavaMail來實現電子郵件的發送等。 Outlook作為微軟提供的企業電子…

【YOLOs-CPP-圖像分類部署】03-解決報錯

完整項目鏈接 點擊here下載! 上一篇問題 經過上一篇博客,我們得到了一個粗略版(會報錯)的項目。如何解決異常報錯呢? 我把問題在github上對作者進行了提問,但是2天后,依然沒有回復。 怎么辦呢?只能自己調試代碼了。 修改代碼 經過大量調試,修改了YOLO11CLASS.h…

Dockers Compose常用指令介紹

Dockers Compose常用指令 1、常用指令介紹 1.1、version 指令 頂級一級指令&#xff0c;指定 compose 指定文件格式版本 version: "3.8" services: 不同版本支持的功能不同。常用版本有 ‘2’, ‘3’, ‘3.8’ 等。 1.2、services 指令 頂級一級指令&#xff0…

謝飛機的Spring WebFlux面試之旅:從基礎到深入

謝飛機的Spring WebFlux面試之旅&#xff1a;從基礎到深入 面試場景&#xff1a;謝飛機的WebFlux面試 面試官&#xff1a;你好&#xff0c;謝飛機&#xff0c;請介紹一下你自己。 謝飛機&#xff1a;您好&#xff0c;我是一名有三年開發經驗的Java程序員&#xff0c;熟悉Spr…

Mysql增量備份與恢復

1.練習數據增量備份 增量備份&#xff1a;備份上次備份后&#xff0c;新產生的數據。 PERCONA Xtrabackup是一款強大的在線熱備份工具&#xff0c;備份過程中不鎖庫表&#xff0c;適合生產環境。支持完全備份與恢復、增量備份與恢復、差異備份與恢復。 安裝Xtrabackup 150、…