TCP協議為什么可靠?

我們都知道,TCP和UDP協議的區別在于TCP可以提供可靠的網絡數據傳輸,但UDP不能。

為什么TCP比較可靠呢?可能有人會回答,TCP是面向連接的,而UDP不是。連接是什么呢?它是一個像水管一樣的東西,把所有的數據往連接里一放就保證了數據完整有序到達嗎?其實不是的。

TCP/IP詳解對整個數據傳輸過程有著詳細的說明。我試著把其中關鍵的部分抽取出來,解釋一下TCP協議到底是怎么保證傳輸的可靠性的。

建立連接

連接是什么

當提到連接,我們本能的會把它想成一根水管或者繩子,建立連接就是把這個水管或者繩子接起來。在通信的時候,我們會把連接想象成一個獨立的通道,建立連接后所有的數據都順著這個通道傳輸出去,對方就能收到有序完整的數據。但是實際上,因為各種各樣的問題(硬件故障、網絡阻塞、攻擊等)的存在,網絡傳輸通道本身就不可靠。
所以,TCP里的所謂連接不是一個通道,它只是通信雙方建立的一個一對一的邏輯關系,讓雙方都明確對方是自己的通信目標。

既然雙方只存在邏輯約定,數據仍然可能在傳輸過程中會出現錯誤、丟失等各種狀況。那建立連接的意義是什么呢?舉個例子:

如果一開始雙方沒有建立連接的那幾步溝通,乙不知道甲到底要干什么,也不知道甲說的內容從什么地方開始到什么地方結束,甲乙就都沒法確保這次通信的完整和正確。

更多的細節可以參考到底什么是TCP連接?

三次握手建立連接

TCP通過三次握手的方式建立連接,具體的過程見下圖:

從圖中可以看到,三次握手的過程其實是一個客戶端和服務器各向對方發送一個數seq,并接收對方的ACK(收到的seq+1)的過程。第二次握手的數據里同時包含了服務器給客戶端的ACK和服務器發出的seq。
三次握手以后,連接雙方就同時進入ESTABLISHED(連接成功)狀態,準備開始數據傳輸。

如果想知道三次握手建立連接,或者四次揮手斷開連接的更多細節,可以看看簡析TCP的三次握手與四次分手這篇文章。
另外,知乎上為什么TCP是三次握手,而不是兩次或者四次握手這個問題,解釋了三次握手的設計初衷,值得一看。

傳輸數據

ACK機制

由于通信過程的不可靠性,傳輸的數據不可避免的會出現丟失、延遲、錯誤、重復等各種狀況,TCP協議為解決這些問題設計了一系列機制。
這個機制的核心,就是發送方向接收方發送數據后,接收方要向發送方發送ACK(回執)。如果發送方沒接收到正確的ACK,就會重新發送數據直到接收到ACK為止。
比如:發送方發送的數據序號是seq,那么接收方會發送seq + 1作為ACK,這樣發送方就知道接下來要發送序號為seq + 1的數據給接收方了。

我們來看看在不同的異常情況下,ACK機制是怎么工作的:

  • 數據丟失或延遲。發送方發送數據seq時會起一個定時器,如果在指定時間內沒有接收到ACK seq + 1,就把數據seq再發一次。
  • 數據亂序。接收方上一個收到的正確數據是seq + 4,它返回seq + 5作為ACK。這時候它收到了seq + 7,因為順序錯了,所以接收方會再次返回seq + 5給發送方。
  • 數據錯誤。每一個TCP數據都會帶著數據的校驗和。接收方收到數據seq + 3以后會先對校驗和進行驗證。如果結果不對,則發送ACK seq + 3,讓發送方重新發送數據。
  • 數據重復。接收方直接丟棄重復的數據即可。

ACK的優化

按照ACK機制,只要整個數據傳輸順利結束,接收方就能收到完整有序的數據了。但是,如果我們針對每一個數據包都發送ACK,就會有大量的網絡資源消耗在ACK的發送上,這不太劃算的。于是,TCP設計了延遲ACK的機制。

這個機制其實很簡單。客戶端一次給服務器發送多個數據包,當服務器收到客戶端的數據包時,不馬上發送ACK,而是稍微等一小段時間。在這個過程中服務器可能能收到后續幾個數據包,服務器就可以直接按照最后一個正確的數據發送ACK,減少發送ACK的總數。

除了延遲ACK的機制,TCP還做了很多對傳輸過程的優化,比如滑動窗口機制,比如慢啟動機制。由于跟本文的主題無關,我就不在這里多說了,有興趣的同學可以搜索來看看。


本人學識有限,文中難免有不嚴謹或者錯誤出現,希望各位讀者能幫忙指出,感謝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 傳輸層-TCP, TCP頭部結構 ,TCP序列號和確認號詳解 TCP主要解決下面的三個問題 1.數據的可靠傳輸...
    抓兔子的貓閱讀 4,555評論 1 46
  • 個人認為,Goodboy1881先生的TCP /IP 協議詳解學習博客系列博客是一部非常精彩的學習筆記,這雖然只是...
    貳零壹柒_fc10閱讀 5,096評論 0 8
  • 1、TCP狀態linux查看tcp的狀態命令:1)、netstat -nat 查看TCP各個狀態的數量2)、lso...
    北辰青閱讀 9,528評論 0 11
  • 套接字選項SO_RESUEADDR 即使端口處于2MSL狀態,使用該選項,仍然能夠在該端口建立連接。服務器常會設置...
    Myth52125閱讀 1,446評論 0 0
  • 1.這篇文章不是本人原創的,只是個人為了對這部分知識做一個整理和系統的輸出而編輯成的,在此鄭重地向本文所引用文章的...
    SOMCENT閱讀 13,137評論 6 174