TCP在網絡協議(網絡協議見這篇文章)中是非常重要的,要說有多重要的話,那就像珍珠奶茶的奶茶一樣。
1. 三次握手
TCP在進行數據的傳輸之前必須先建立連接,建立之后才能進行數據的傳輸,那么所謂的建立連接是怎么回事呢?來看下其三次握手。

- 客戶端發送SYN和seq序列號,SYN為標識位,意思為請求同步,seq是此次包的序列號,序列號是單調遞增的,作用是保證傳輸的可靠性,在丟包的時候能確定丟的是哪個包。
 - 服務端收到消息之后,發送確認的信息,包括標識位SYN和ACK(表確認作用)、確認信息ack=客戶端發送的seq+1,seq=自己的seq。seq和ack的確認機制知道確認的是哪個包。
 - 客戶端收到服務端的確認消息(也是請求同步的信息)之后,回復其同步消息,發送ACK=1和ack=服務端的seq+1還有自己的seq(值為第一次的seq+1,要單調遞增),此時客戶端這邊的連接已經完成了。
 - 服務端接收到客戶端的消息之后,服務端這邊的連接也完成,至此三次握手圓滿結束,接下來就可以傳輸數據了。
 
 三次握手的流程並不復雜,概括就是:客戶端向服務端發送同步請求,服務端確認並向客戶端發送同步請求,客戶端確認,連接完成。
 但是在這簡單的流程中有幾個問題需要思考:
- 為什么需要三次握手?
 - 服務端有超時重傳機制嗎?確認包發送之后一段時間沒收到響應會重發嗎,還是等待客戶端重發包。
 - 客戶端收到服務端的確認消息之后能發送數據嗎,即第二次握手完成的時候客戶端能向服務端發送數據嗎?
 
 上面這些問題是不是除了第一個其他的都沒想過?你可能會說,"那肯定啊,誰沒事去想這玩意,我學TCP都是為了面試的時候能夠把三次握手和四次揮手說出來。"
 哼!對於這種想法,我只能說:

 不過如果想造火箭,自己總不能是一顆汽車的輪子吧(布加迪威龍除外),所以必要的思考很重要。那來看看這幾個問題
-  
為什么要三次握手?
答:因為四這個數字不吉利。

 開個玩笑,麻煩把磚頭收一收。首先我們得理解TCP是雙方的連接,也就是說只有確定客戶端和服務端的發送和接收都是沒問題的這個連接才算完成。那來看下,第一次握手略過,第二次握手也就是客戶端接收到服務端的確認消息時,這里證明了兩個問題:
- 服務端的確認消息中的ack是自己的seq+1,說明服務端收到了自己剛才發的包並且能夠明白。
 - 自己收到確認消息說明服務端的發送端正常,自己的接收端正常。
 
 到第二次握手這里已經證明了三個所需條件:客戶端的發送和接收正常、服務端的發送正常。還少一個服務端的接收,所以客戶端要再發一次給服務端的確認包,讓服務端也知道其發送和接收是正常的,所以總共是三次。
 -  
服務端有超時重傳機制嗎?
 有的,如剛才所說,TCP是雙端的協議,服務端是接收方也是發送方,所以是有超時重傳的機制。比如說第三次握手客戶端向服務端發送消息時由於網絡原因丟包了,那么服務端一段時間后沒收到消息就會重發。
 -  
客戶端收到服務端的確認消息之后能發送數據嗎?
 意思就是說,在第二次握手完成后,客戶端能不能向服務端發送數據。在回答這個問題之前,我先問一個問題,這時候客戶端這邊已經確認發送和接收沒問題了,現在不能發,什么時候能發呢?所以是可以的,服務端接收到發送的數據之后進行判斷,如果此時服務端還沒收到第三次握手,則對當前接收的包不處理(即丟棄),然后重發一次第二次握手請求;否則正常接收數據。
 三次握手結束之后,就可以進行數據的傳輸,這里有長連接和短連接之分。可能放在這里比較陌生,但是另一個協議——HTTP的長連接和短連接應該都知道了,其本質就是TCP的長連接和短連接,而且作用是一樣的,短連接在發送一次數據后就進行關閉,長連接則保持直到主動選擇關閉分開。
說到分開,讓我不由得想起那一年四月,夕陽淌在她的臉上,她用纖細的手指挽起了耳邊的秀發,轉過頭對我說:"我們之間已經沒有什么能給對方的了,總要一個人先開口,就像TCP'四次揮手'一樣!"
 醒醒,程序猿哪里有女朋友。 

2. 四次揮手
 不知道怎么開頭,先給大家看個寶貝吧。

 看了這張圖都是字母,即便你告訴我這就是四次揮手,但這就像JOJO一樣,一開始我是難以接受的。沒有關系,魯迅說過,"四次揮手比起機械的記憶,嘗試去理解帶來的性價比可能要高得多。"
 我們一開始也說過,TCP是雙方的協議,所以雙方要有溝通,這樣才能正確的關閉通道。而TCP的溝通,是這樣的:
客戶端:"我這邊數據發完了,我要把我這邊的發送通道關了,你看下你那邊有沒有什么問題。"
服務端:"嗯,我數據接收完了,你關吧,我把我這邊的接收通道也關了。"
 okay,這樣客戶端關閉了發送通道,服務端關閉了接收通道(注意,只能由發送通道發起聊天)。過了一段時間后,服務端這邊的數據也都傳輸完了,他也想關閉了。
服務端:"我這邊的數據也發完了,我這邊把發送通道關了就下班了,你還有什么問題嗎?"
客戶端:"我這邊也接收完了,你關吧,我也把這邊的接收通道關了。等下下班后一起去修車嗎?"
此時客戶端還不能直接關完走人,因為他不知道修車地址啊(可惡)。說錯了,是他擔心服務端沒收到他的消息,那需要等他個2MSL吧,如果服務端真的沒收到會重新發信息過來的,到時候我再發一次就行。
 到這里再回過頭來看上面那張圖。emem,是不是完全搞懂了。

 (不理解再慢慢看看)個人覺得圖中最重要的應該是TIME_WAIT狀態,以及為什么要等2MSL,順便說下MSL是報文單位,不想懂可以理解為另一種意義的秒。
 所以以后再被問為什么要四次揮手?你就說為了一起修車(不是)。
3. TCP是如何保證可靠性的
 當我們被問到TCP和UDP的區別時,我們總會回答:"TCP是可靠的,而UDP是不可靠的。"但TCP為什么是可靠的,是怎么保證其可靠性的可能就沒那么多人知道了。
- 校驗和
 - 序號和確認應答:
 - 超時重傳
 - TCP不處理重復的包
 - ARQ協議
 - 流量控制
 - 擁塞控制
 
 上面這些就是TCP可靠性的基石,來看下這些基石長什么樣。
-  
校驗和
 將頭部和數據通過一個算法得到一個結果,這個結果就是校驗和。校驗和是防止包在傳輸的過程中被修改,接收端接收到包也會通過特定的算法來檢測校驗和是否能對上。
 -  
序號和確認應答
 這在上方三次握手的時候也有涉及到,意思就是在發送方每次發送的包都是有序號的,如果包丟了,就要重新發下這個序號對應的包,而確認應答機制可以做到讓發送端知道該重發的是哪個包。

 如上圖,在傳輸的過程中,如果中途丟了一個包,例如上圖的11-20的包,那么接收方就會不斷的確認1-10的包,即便收到21-30的包,發送方收到三次這樣的確認之后便判定包已丟失進行重發。
 -  
超時重傳
 這就沒什么好說的,無論是服務端還是客戶端在發送之后都會啟動一個定時器,一段時間之后沒收到確認定時器就會觸發重發。
 -  
TCP不處理重復的包
 假設現在網絡很慢,客戶端發了消息之后一直沒收到回復,就會重發,兩次或者更多次,而且發的是同一個序號的包,那么這時服務端可能先收到一個包,進行處理后發送確認消息,之后又收到了同一個序號的包,此時便不做處理,直接丟棄,對於后面來的相同序號的包也執行相同的操作。
 -  
連續ARQ協議
 TCP采用的是連續ARQ協議,大致的意思就是說,有數據不馬上發,等待湊齊一定數量或者到了最大等待時間再發,湊齊一定的數量稱為一組,而連續ARQ協議就是說不用等待確認消息再發下一組,可以連續發多組。(ARQ協議還有另外一種,有興趣的可以自己了解下)
 -  
流量控制
 在介紹流量控制之前,先提出一個問題:服務端有沒有可能出現接收不過來的情況?肯定有,不然我接下來的內容怎么寫。
 那么如果出現這樣的情況,會有怎么樣的后果呢?
服務端處理不過來,給客戶端的響應就會變慢,而客戶端收不到響應觸發超時重傳,哦吼,服務端本來就忙不過來,你還一直施加壓力,這不是讓服務端往死路逼嘛。

而流量控制,就是為了解決這種問題的。那么流量控制究竟做了什么呢?
首先,發送方和接收方雙發之間都維護了一個窗口,叫滑動窗口。接收方的窗口規定了還能接收多少數據,而發送方的窗口則規定了還能發送多少數據。接收方在回復確認信息的時候會將其能接收的大小發給發送方,發送方的窗口大小則取最小值Math.min{接收窗口大小,網絡窗口大小(下個節點講)}。如果接收窗口的大小為0,那么發送方將不再傳輸數據,而是采用發送探測包的形式檢測是否能繼續發送數據。
 -  
擁塞控制
假設有這樣一個場景:
客戶端發出了一個包,由於網絡原因,導致了重發,但還是得不到響應,所以就不斷的重發,在這停住,然后把視野抽出來,看到有幾億個客戶端如此,繼續放送,現在會發生什么呢?
原本網絡由於某些原因可能只有一點堵塞,但是由於n個客戶端進行了多次的重發操作,導致一下子就擁堵了起來,擁堵又會導致更多的客戶端超時而重發,從而進入一個惡性循環,這,自然是不行的。
那咋辦呢?還能咋辦,遇事不決,限流解決。限流要限多少呢?無論定多少都感覺會錯,那從1開始逐漸逐漸往上升,總能有一個是對的吧?好想法!!!於是便有了慢啟動算法,見下圖。

(此圖片來源網絡,若有侵權聯系我刪除)首先,發送方不是一下子發送所有數據,而是從小事做起,先發一個,如果正常那么發兩倍,如此如此,直到到了一個閾值,如上圖中的16,此時不能再兩倍發了(因為再這樣很容易就超時),所以+1發,就這樣一直到到超時。如果發生了超時,閾值調整為發生超時時的一半,並且發送方從1開始按照上方的算法繼續走。這就是慢啟動算法。
注意發送方能發的包大小還得看另一個參數——接收方的接收窗口大小,見上方流量控制的介紹。發送方的發送數據大小=min{接收方接收窗口,慢啟動算法網絡窗口},也就是兩個之間的最小值。
有了上面這些,還有誰能質疑TCP的可靠性呢?
 

如果覺得文章對你有幫忙,希望關注沒事。[雙手合十]
參考:
https://blog.csdn.net/sinat_36629696/article/details/80740678
