硬不硬你說了算!35 張圖解被問千百遍的 TCP 三次握手和四次揮手面試題

来源:https://www.cnblogs.com/xiaolincoding/archive/2020/04/05/12638546.html
-Advertisement-
Play Games

每日一句英語學習,每天進步一點點: 前言 不管面試 Java 、C/C++、Python 等開發崗位, TCP 的知識點可以說是的必問的了。 任 TCP 虐我千百遍,我仍待 TCP 如初戀。 遙想小林當年校招時常因 TCP 面試題被刷,真是又愛又狠…. 過去不會沒關係,今天就讓我們來消除這份恐懼,微 ...


每日一句英語學習,每天進步一點點:

前言

不管面試 Java 、C/C++、Python 等開發崗位, TCP 的知識點可以說是的必問的了。

任 TCP 虐我千百遍,我仍待 TCP 如初戀。

遙想小林當年校招時常因 TCP 面試題被刷,真是又愛又狠….

過去不會沒關係,今天就讓我們來消除這份恐懼,微笑著勇敢的面對它吧!

所以小林整理了關於 TCP 三次握手和四次揮手的面試題型,跟大家一起探討探討。

  1. TCP 基本認識
  1. TCP 連接建立
  1. TCP 連接斷開
  1. Socket 編程

PS:本次文章不涉及 TCP 流量控制、擁塞控制、可靠性傳輸等方面知識,這些留在下篇哈!


正文

01 TCP 基本認識

瞧瞧 TCP 頭格式

我們先來看看 TCP 頭的格式,標註顏色的表示與本文關聯比較大的欄位,其他欄位不做詳細闡述。

TCP 頭格式TCP 頭格式

序列號:在建立連接時由電腦生成的隨機數作為其初始值,通過 SYN 包傳給接收端主機,每發送一次數據,就「累加」一次該「數據位元組數」的大小。用來解決網路包亂序問題。

確認應答號:指下一次「期望」收到的數據的序列號,發送端收到這個確認應答以後可以認為在這個序號以前的數據都已經被正常接收。用來解決不丟包的問題。

控制位:

  • ACK:該位為 1 時,「確認應答」的欄位變為有效,TCP 規定除了最初建立連接時的 SYN 包之外該位必須設置為 1
  • RST:該位為 1 時,表示 TCP 連接中出現異常必須強制斷開連接。
  • SYC:該位為 1 時,表示希望建立連,併在其「序列號」的欄位進行序列號初始值的設定。
  • FIN:該位為 1 時,表示今後不會再有數據發送,希望斷開連接。當通信結束希望斷開連接時,通信雙方的主機之間就可以相互交換 FIN 位置為 1 的 TCP 段。

為什麼需要 TCP 協議? TCP 工作在哪一層?

IP 層是「不可靠」的,它不保證網路包的交付、不保證網路包的按序交付、也不保證網路包中的數據的完整性。

OSI 參考模型與 TCP/IP 的關係OSI 參考模型與 TCP/IP 的關係

如果需要保障網路數據包的可靠性,那麼就需要由上層(傳輸層)的 TCP 協議來負責。

因為 TCP 是一個工作在傳輸層可靠數據傳輸的服務,它能確保接收端接收的網路包是無損壞、無間隔、非冗餘和按序的。

什麼是 TCP ?

TCP 是面向連接的、可靠的、基於位元組流的傳輸層通信協議。

  • 面向連接:一定是「一對一」才能連接,不能像 UDP 協議 可以一個主機同時向多個主機發送消息,也就是一對多是無法做到的;

  • 可靠的:無論的網路鏈路中出現了怎樣的鏈路變化,TCP 都可以保證一個報文一定能夠到達接收端;

  • 位元組流:消息是「沒有邊界」的,所以無論我們消息有多大都可以進行傳輸。並且消息是「有序的」,當「前一個」消息沒有收到的時候,即使它先收到了後面的位元組已經收到,那麼也不能扔給應用層去處理,同時對「重覆」的報文會自動丟棄。

什麼是 TCP 連接?

我們來看看 RFC 793 是如何定義「連接」的:

Connections: The reliability and flow control mechanisms described above require that TCPs initialize and maintain certain status information for each data stream. The combination of this information, including sockets, sequence numbers, and window sizes, is called a connection.

簡單來說就是,用於保證可靠性和流量控制維護的某些狀態信息,這些信息的組合,包括Socket、序列號和視窗大小稱為連接。

所以我們可以知道,建立一個 TCP 連接是需要客戶端與伺服器端達成上述三個信息的共識。

  • Socket:由 IP 地址和埠號組成
  • 序列號:用來解決亂序問題等
  • 視窗大小:用來做流量控制

如何唯一確定一個 TCP 連接呢?

TCP 四元組可以唯一的確定一個連接,四元組包括如下:

  • 源地址
  • 源埠
  • 目的地址
  • 目的埠
TCP 四元組TCP 四元組

源地址和目的地址的欄位(32位)是在 IP 頭部中,作用是通過 IP 協議發送報文給對方主機。

源埠和目的埠的欄位(16位)是在 TCP 頭部中,作用是告訴 TCP 協議應該把報文發給哪個進程。

有一個 IP 的伺服器監聽了一個埠,它的 TCP 的最大連接數是多少?

伺服器通常固定在某個本地埠上監聽,等待客戶端的連接請求。

因此,客戶端 IP 和 埠是可變的,其理論值計算公式如下:

對 IPv4,客戶端的 IP 數最多為 232 次方,客戶端的埠數最多為 216 次方,也就是服務端單機最大 TCP 連接數,約為 248 次方。

當然,服務端最大併發 TCP 連接數遠不能達到理論上限。

  • 首先主要是文件描述符限制,Socket 都是文件,所以首先要通過 ulimit 配置文件描述符的數目;
  • 另一個是記憶體限制,每個 TCP 連接都要占用一定記憶體,操作系統是有限的。

UDP 和 TCP 有什麼區別呢?分別的應用場景是?

UDP 不提供複雜的控制機制,利用 IP 提供面向「無連接」的通信服務。

UDP 協議真的非常簡,頭部只有 8 個位元組( 64 位),UDP 的頭部格式如下:

UDP 頭部格式UDP 頭部格式
  • 目標和源埠:主要是告訴 UDP 協議應該把報文發給哪個進程。
  • 包長度:該欄位保存了 UDP 首部的長度跟數據的長度之和。
  • 校驗和:校驗和是為了提供可靠的 UDP 首部和數據而設計。

TCP 和 UDP 區別:

1. 連接

  • TCP 是面向連接的傳輸層協議,傳輸數據前先要建立連接。
  • UDP 是不需要連接,即刻傳輸數據。

2. 服務對象

  • TCP 是一對一的兩點服務,即一條連接只有兩個端點。
  • UDP 支持一對一、一對多、多對多的交互通信

3. 可靠性

  • TCP 是可靠交付數據的,數據可以無差錯、不丟失、不重覆、按需到達。
  • UDP 是盡最大努力交付,不保證可靠交付數據。

4. 擁塞控制、流量控制

  • TCP 有擁塞控制和流量控制機制,保證數據傳輸的安全性。
  • UDP 則沒有,即使網路非常擁堵了,也不會影響 UDP 的發送速率。

5. 首部開銷

  • TCP 首部長度較長,會有一定的開銷,首部在沒有使用「選項」欄位時是 20 個位元組,如果使用了「選項」欄位則會變長的。
  • UDP 首部只有 8 個位元組,並且是固定不變的,開銷較小。

TCP 和 UDP 應用場景:

由於 TCP 是面向連接,能保證數據的可靠性交付,因此經常用於:

  • FTP 文件傳輸
  • HTTP / HTTPS

由於 UDP 面向無連接,它可以隨時發送數據,再加上UDP本身的處理既簡單又高效,因此經常用於:

  • 包總量較少的通信,如 DNSSNMP
  • 視頻、音頻等多媒體通信
  • 廣播通信

為什麼 UDP 頭部沒有「首部長度」欄位,而 TCP 頭部有「首部長度」欄位呢?

原因是 TCP 有可變長的「選項」欄位,而 UDP 頭部長度則是不會變化的,無需多一個欄位去記錄 UDP 的首部長度。

為什麼 UDP 頭部有「包長度」欄位,而 TCP 頭部則沒有「包長度」欄位呢?

先說說 TCP 是如何計算負載數據長度:

其中 IP 總長度 和 IP 首部長度,在 IP 首部格式是已知的。TCP 首部長度,則是在 TCP 首部格式已知的,所以就可以求得 TCP 數據的長度。

大家這時就奇怪了問:“ UDP 也是基於 IP 層的呀,那 UDP 的數據長度也可以通過這個公式計算呀? 為何還要有「包長度」呢?”

這麼一問,確實感覺 UDP 「包長度」是冗餘的。

因為為了網路設備硬體設計和處理方便,首部長度需要是 4位元組的整數倍。

如果去掉 UDP 「包長度」欄位,那 UDP 首部長度就不是 4 位元組的整數倍了,所以小林覺得這可能是為了補全 UDP 首部長度是 4 位元組的整數倍,才補充了「包長度」欄位。

02 TCP 連接建立

TCP 三次握手過程和狀態變遷

TCP 是面向連接的協議,所以使用 TCP 前必須先建立連接,而建立連接是通過三次握手而進行的。

TCP 三次握手TCP 三次握手
  • 一開始,客戶端和服務端都處於 CLOSED 狀態。先是服務端主動監聽某個埠,處於 LISTEN 狀態
第一個報文—— SYN 報文第一個報文—— SYN 報文
  • 客戶端會隨機初始化序號(client_isn),將此序號置於 TCP 首部的「序號」欄位中,同時把 SYN 標誌位置為 1 ,表示 SYN 報文。接著把第一個 SYN 報文發送給服務端,表示向服務端發起連接,該報文不包含應用層數據,之後客戶端處於 SYN-SENT 狀態。
第二個報文 —— SYN + ACK 報文第二個報文 —— SYN + ACK 報文
  • 服務端收到客戶端的 SYN 報文後,首先服務端也隨機初始化自己的序號(server_isn),將此序號填入 TCP 首部的「序號」欄位中,其次把 TCP 首部的「確認應答號」欄位填入 client_isn + 1, 接著把 SYNACK 標誌位置為 1。最後把該報文發給客戶端,該報文也不包含應用層數據,之後服務端處於 SYN-RCVD 狀態。
第三個報文 —— ACK 報文第三個報文 —— ACK 報文
  • 客戶端收到服務端報文後,還要向服務端回應最後一個應答報文,首先該應答報文 TCP 首部 ACK 標誌位置為 1 ,其次「確認應答號」欄位填入 server_isn + 1 ,最後把報文發送給服務端,這次報文可以攜帶客戶到伺服器的數據,之後客戶端處於 ESTABLISHED 狀態。

  • 伺服器收到客戶端的應答報文後,也進入 ESTABLISHED 狀態。

從上面的過程可以發現第三次握手是可以攜帶數據的,前兩次握手是不可以攜帶數據的,這也是面試常問的題。

一旦完成三次握手,雙方都處於 ESTABLISHED 狀態,此致連接就已建立完成,客戶端和服務端就可以相互發送數據了。

如何在 Linux 系統中查看 TCP 狀態?

TCP 的連接狀態查看,在 Linux 可以通過 netstat -napt 命令查看。

TCP 連接狀態查看TCP 連接狀態查看

為什麼是三次握手?不是兩次、四次?

相信大家比較常回答的是:“因為三次握手才能保證雙方具有接收和發送的能力。”

這回答是沒問題,但這回答是片面的,並沒有說出主要的原因。

在前面我們知道了什麼是 TCP 連接

  • 用於保證可靠性和流量控制維護的某些狀態信息,這些信息的組合,包括Socket、序列號和視窗大小稱為連接。

所以,重要的是為什麼三次握手才可以初始化Socket、序列號和視窗大小並建立 TCP 連接。

接下來以三個方面分析三次握手的原因:

  • 三次握手才可以阻止重覆歷史連接的初始化(主要原因)
  • 三次握手才可以同步雙方的初始序列號
  • 三次握手才可以避免資源浪費

原因一:避免歷史連接

我們來看看 RFC 793 指出的 TCP 連接使用三次握手的首要原因

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

簡單來說,三次握手的首要原因是為了防止舊的重覆連接初始化造成混亂。

網路環境是錯綜複雜的,往往並不是如我們期望的一樣,先發送的數據包,就先到達目標主機,反而它很騷,可能會由於網路擁堵等亂七八糟的原因,會使得舊的數據包,先到達目標主機,那麼這種情況下 TCP 三次握手是如何避免的呢?

三次握手避免歷史連接三次握手避免歷史連接

客戶端連續發送多次 SYN 建立連接的報文,在網路擁堵等情況下:

  • 一個「舊 SVN 報文」比「最新的 SYN 」 報文早到達了服務端;
  • 那麼此時服務端就會回一個 SYN + ACK 報文給客戶端;
  • 客戶端收到後可以根據自身的上下文,判斷這是一個歷史連接(序列號過期或超時),那麼客戶端就會發送 RST 報文給服務端,表示中止這一次連接。

如果是兩次握手連接,就不能判斷當前連接是否是歷史連接,三次握手則可以在客戶端(發送方)準備發送第三次報文時,客戶端因有足夠的上下文來判斷當前連接是否是歷史連接:

  • 如果是歷史連接(序列號過期或超時),則第三次握手發送的報文是 RST 報文,以此中止歷史連接;
  • 如果不是歷史連接,則第三次發送的報文是 ACK 報文,通信雙方就會成功建立連接;

所以, TCP 使用三次握手建立連接的最主要原因是防止歷史連接初始化了連接。

原因二:同步雙方初始序列號

TCP 協議的通信雙方, 都必須維護一個「序列號」, 序列號是可靠傳輸的一個關鍵因素,它的作用:

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

-Advertisement-
Play Games
更多相關文章
  • 1.環境部署 | 安裝軟體 | 主機名 |IP地址|記憶體需求| | | | | | | Elasticsearch | mes |192.168.13.142|至少3G| |Logstash|log|192.168.13.143|至少2G| |head,Kibana|head kib|192.168 ...
  • 1.Svn 1.Svn簡介 2.搭建過程 2.部署Svn 準備兩台機器,一臺做服務端,一臺做客戶端。 1.服務端搭建 2.客戶端測試 如果報錯: 原因:svn服務未啟動或者是啟動的時候未指定svn倉庫路徑,svn預設倉庫路徑為/var/svn,所以我們需要手動指定為/home/svn/ 解決方案: ...
  • 先上一張圖 FATAL Error: listen EADDRNOTAVAIL 123.57.251.57:5601 配置文件我是這樣配置的: 因為用的是雲虛擬機,所以這裡的123.57.251.57是外網ip,我們應該用內網ip才行。 但是如果寫localhost的話,雖然不會報錯,5601埠也 ...
  • 1.環境以及依賴包的安裝 2.下載並安裝 3.檢測nginx配置文件是否正確 4.啟動nginx服務 下麵是一些編譯參數和配置文件的詳細說明 5.各個編譯參數 6.配置文件 7.nginx安裝時的一些常用命令 我這裡已經建立過軟連接了,所以直接用的nginx命令 你們的評論和點贊是我寫文章的最大動力 ...
  • 1.查看現有的 nginx 編譯參數 2.上傳新版本的源碼包nginx 1.16.1.tar.gz,解壓到/usr/local/ (註意:按照原來的編譯參數安裝 nginx 的方法進行安裝, 只需要到 make,千萬不要 make install 。如果make install 會將原來的配置文件覆 ...
  • 1.IPtables介紹 Iptables(以下簡稱Iptables)是unix/linux自帶的一款優秀且開放源代碼的完全自由的基於包過濾(對OSI模型的四層或者是四層以下進行過濾)的防火牆工具,它的功能十分強大,使用非常靈活,可以對流入和流出伺服器的數據包進行很精細的控制。 iptables工作 ...
  • 1.RabbitMQ簡介 消息中間件也可以稱消息隊列,是指用高效可靠的消息傳遞機制進行與平臺無關的數據交流,並基於數據通信來進行分散式系統的集成。通過提供消息傳遞和消息隊列模型,可以在分散式環境下擴展進程的通信。 RabbitMQ是使用Erlang語言開發的開源消息隊列系統, 基於AMQP協議來實現 ...
  • 最近被shell里的各種括弧弄的有點暈了,又是小括弧又是中括弧,有時又有花括弧,小括弧和中括弧還有雙層寫法,用途各不一樣,我搞混了多次,對它們的用法有些迷糊了,於是我在這裡整理一下。如有錯誤,望諸君指正。 小括弧系列 [toc] () 用途:數組初始化 $() 用途:引用命令的運行結果 (()) 用 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...