1、概述
TCP協議全名是 Transport Control Protocol
,是一個可以提供 可靠的、支持全雙工、連接導向的協議,因此在客戶端和服務端之間傳輸數據的時候,是必須先建立連接的。
1.1、什么是建立連接
- 連接本身是個虛擬、抽象的概念。他能讓兩個通信的程序之間確保彼此都在線
- 建立連接可以加快相應請求的速度
- 連接也被稱為 會話(Session)
- 建立連接可以使得通信更加的穩定、安全
- 但是同樣建立連接也會消耗相應的資源
1.2、單工、半雙工、全雙工
- 單工: 任何時刻數據只能單向傳輸
- 半雙工:允許數據在兩個方向上傳輸, 但是在某一個時刻(同一時刻),只允許數據在一個方向上傳輸。
- 全雙工: 任何時刻數據都可以雙向傳輸。
1.3、可靠性
- 可靠性是為了保證數據的無損傳輸
- 使用無序的數據恢復原有順序
- 多播時每個接收方都獲得無損的副本。
2、特點
-
1、基於連接的(點對點的通信)
- 傳輸數據之前是要建立好連接的
-
2、是雙工通信的
- TCP協議一旦建立連接, 就可以在連上上實現雙向的通信
-
3、基於字節流而非報文--保證了TCP協議的可靠性
- 將數據按字節大小進行編號,接收端通過ACK來確認收到的數據編號,通過這個機制保證TCP協議的有序性和完整性
-
4、擁塞控制
- TCP協議通過 慢啟動、擁塞避免、擁塞發生、快速恢復 在不同的過程中的算法來控制擁塞的
-
5、流量控制能力
- 通過滑動窗口控制數據的發生速率,滑動窗口的本質是動態緩沖區,接收區根據自己的能力在 TCP 的請求頭header中動態調整窗口大小,通過ACK應答包通知到給發送端,發送端根據窗口的大小調控發送速率。
3、TCP協議詳解
在解釋TCP工作流程之前呢, 先解釋一下幾個名詞,這樣更有助於我們去了解其過程。
3.0、TCP首部信息組成以及各個部分的作用
下圖是TCP協議報文段的組成圖片
3.0.1、源端口和目的端口
- 源端口,用來存放 發送TCP報文的進程對應的端口號。占 2個字節(16位)
- 目的端口,用來存放 接受TCP報文段的進程對應的端口號。 占 2個字節(16位)
3.0.2、32位序列號 Sequence Number
- 占用4個字節(一個字節(byte)8個比特位(bit))。
- TCP的序列號對數據包進行標記,以便達到目的地后重新組裝數據包,假設當前序列號為
s
,發送數據長度為l
,則下一次發送數據時的序列號為s+l
。 - 在建立連接時通常由計算機生成隨機數作為序列號的初始值。
3.0.3、32位確認號 Acknowledgement Number
- 占用 4個字節(一個字節(byte)8個比特位(bit))
- 是有接收端計算機使用,用於重組分組的報文成最初形式。
- 如果設置了ACK控制位, 那么這個值表示准備接受的下一個包的序列號
3.0.4、數據偏移 offset
- 占用4位,即0.5個字節
- 這部分實際上是指出TCP報文的首部的長度,即TCP報文段數據起始位置距離TCP報文的起始位置有多遠(這里指 TCP拆包后的報文段的起始位置 與 TCP整個報文的起始位置有多遠)
3.0.5、保留字 Reserved
- 占6位,即 0.75個字節
- 保留為以后使用,當前是值為零。
3.0.6、標志位 Tcp Flags
- 每個標志位占1 位,一共6個標志位 。即 1.5個字節。
- URG - 緊急指針有效標識
- 此標志位用來表示TCP包的緊急指針域有效,用來保證TCP連接不會被終端,並且督促中間層設備要盡快處理這些數據。相當於告訴接收端,有高優先級的數據。
- ACK - 確認序號有效標識
- 只有當
ACK=1
的時候,確認號字段才有效。 - 當
ACK=0
的時候,確認號是無效的。
- 只有當
- PSH - 用來表示接收方應盡快將這個報文段交給應用層
- 接收到
PSH = 1
的TCP報文段, 應盡快的交付接收報文段的應用進程, 而不再等待整個緩存都填滿后再交付
- 接收到
- RST - 重建連接標識
- 當
RST = 1
時,表明TCP連接出現嚴重錯誤(如由於主機崩潰或其他原因),必須釋放連接,然后再重新簡歷連接。
- 當
- SYN - 表示同步序號,用來建立連接。
- 當
SYN = 1
時,表示這是一個連接請求或者連接接受請求。
- 當
- FIN - 發送完成任務標識,用來釋放一個連接
- 當
FIN = 1
表明此報文段的發送端和數據已經發送完成了
- 當
3.0.7、窗口大小 Window Size
- 占 16位 即兩個字節
- 該字段表明指出了現在允許對方發送的數據量,他告訴對方本端TCP連接緩沖區還能容納多少字節的數據,這樣對方就可以控制發送數據的速度。
- 窗口大小的值 指的是 從本報文段的首部中的確認號算起, 接方法目前允許對法發送的數據量。
3.0.8、校驗和 TCP Checksum
- 占用16位,即兩個字節。
- 由發送端填充,接收端對TCP報文段執行CRC算法,以校驗TCP報文段在傳輸過程中是否損壞,如果損壞則丟失。
- 檢驗范圍包括首部和數據兩個部分
- 這也是TCP可靠性的一個重要保障。
3.0.9、緊急指針 Urgent Pointer
- 占用16位,即兩個字節
- 這部分僅在標志位
URG = 1
的時候才有意義,他指出本報文段中的數據的字節數。 - 當
URG = 1
時,發送方TCP就把緊急數據插入到本報文段數據的最前面,而在緊急數據后面任然是普通數據。 - 因此, 緊急指針指出了數據的末尾在報文段中的位置。
3.1、TCP協議的三次握手四次揮手
參考文檔 :https://www.cnblogs.com/qdhxhz/p/8470997.html
先看一下TCP從建立連接到傳輸數據到斷開連接的完整過程
3.1.0、三次握手建立連接的過程
流程如下:
-
第一次握手(由客戶端發起的)
- 客戶端發送
SYN=1 seq = x
的請求建立連接的報文- (SYN 標志位中的同步序列號,用來建立連接的)
- seq 是 32位序列號
Sequence Number
,即在建立連接的時候, 隨機生成的初始序列號x。
- 此時,客戶端進程進入了
SYN-SENT(同步已發送狀態)
狀態 - 此次建立連接的報文是不能攜帶數據的。
- 客戶端發送
-
第二次握手(由服務端發起)
- 服務器接收到請求建立連接的報文后,如果同意連接, 則發出確認報文。
- 標志位
ACK = 1
, 確認號ack = x+1
,這個確認號為 x+1 就是基於上面請求的的seq隨機生成的初始序列號+1得出的。 - 標志位
SYN = 1
, 確認號seq = y
, 這個seq
也是服務端自己隨機生成的一個初始序列號。
- 標志位
- 此時 , 服務器進程進入到
SYN-RCVD(同步收到狀態)
的狀態。 - 這個報文也不能攜帶數據。
- 服務器接收到請求建立連接的報文后,如果同意連接, 則發出確認報文。
-
第三次握手(由客戶端發起)
- 客戶端收到 服務器發送的的確認報文后, 還要再向服務器發送確認報文。
- 標志位
ACK = 1
, 確認號ack = y+1
,序列號seq = x+1
- 標志位
- 此時 TCP連接建立,客戶端和服務端都進入
ESTABLISHED(連接已建立)
狀態。
- 客戶端收到 服務器發送的的確認報文后, 還要再向服務器發送確認報文。
-
舉例解釋一下為什么要三次握手
- 當客戶端發送第一個連接的請求報文, 但是由於網絡不好,這個請求沒有立即到達服務器, 而是在某個節點停留了,知道某個時間才到達服務器,本來這已經是一個失效的報文了, 但是 服務端接收到這個請求報文后,還是會像client 發出確認報文,表示同意建立連接。
- 假設 不采用三次握手,那么只要服務器發出去確認報文,新的連接就建立了,但是其實這個請求已經超時並失效了,客戶端是不會理睬服務器的確認信息的 ,也不會向服務端發送確認的請求。
- 但是此時的服務器是已經認為連接建立了, 換句話說就是處於
ESTABLISHED(連接已建立)
的狀態,並且一直在等待客戶端發來數據。 - 這樣的話, 服務器端就有很多資源浪費了。
- 而采用三次握手的話, 服務端如果收不到確認報文話,就知道客戶端沒有服務端建立連接不成功了。
3.0.2、TCP 數據傳輸過程
客戶端 與 服務端 建立連接之后,就可以相互傳輸數據了。
-
如上圖所示,正常傳輸數據的過程如下:
- 主機A 開始發送數據的時候,假設初始的
seq = 1200
,滑動窗口大小為100,向主機B發送數據傳遞 - 主機B在完全接收到數據后, 為了確認收到 ,需要向主機A 發送ACK包,設置的 值為
1200+100+1
.- ACK = seq + 傳遞數據的字節數 + 1
- 主機A在接收到 主機B 的確認信息后,開始發送下個報文, 此時
seq = 1301
,同樣滑動窗體的大小為100的數據。 - .......
- 注: 與 三次握手協議相同, 最后加1 是為了告訴對象要傳遞 seq信號的。
- 主機A 開始發送數據的時候,假設初始的
-
如上圖所示 , 數據丟包的情況過程如下:
- 在
seq = 1301
數據包向主機B 傳遞 100字節的數據,但中間發生了錯誤,主機B 未收到。 - 經過一段時間的等待后, 主機A 任然未收到
Seq = 1402
的確認號,此時就會嘗試數據重新傳遞。 - 為了完成數據包的重傳, TCP Socket套接字每次發送數據包時都會啟動定時器, 如果在一定時間內沒有收到目標主機的傳回的ACK包, 那么定時器超時, 數據包會重傳。
- 在
3.0.3、四次揮手斷開連接
-
首先TCP連接斷開, 是一個客戶端主動關閉, 服務端被動關閉的過程。
-
關閉連接需要經過4次會話,具體的流程如下:
-
第一次揮手
- TCP 連接的客戶端發送一個 標志位
FIN(結束)=1
的報文,用來請求關閉客戶端到服務端的連接。 - 客戶端進程發出釋放連接的報文。 釋放連接報文的首部,
FIN =1
,其序列號是seq = u
(序列號等於前面已傳送過來的數據的最后一個字節的序號加1) - 客戶端在發送釋放連接的請求后進入
FIN-WAIT-1(終止等待1)
的狀態。 - TCP協議規定, FIN 報文即時不攜帶數據也要消耗一個序號。
- TCP 連接的客戶端發送一個 標志位
-
第二次揮手
- 服務端收到客戶端發送的
FIN
報文時,客戶端會先發送一個ACK(確認)
的報文給客戶端。 - 服務端回復的
ACK
報文中,ACK = 1
,seq = v
,ack = u + 1
。ACK = 1
表示確認報文ack = u + 1
是針對上面第一次揮手服務端的 seq = u 再加上1seq = v
是服務端自己隨機生成的序列號。
- 此時,服務端就進入到
CLOSE-WAIT(關閉等待狀態)
。- TCP 會通知上層應用進程, 客戶端向服務器的方向就釋放了。
- 此時,是處於半關閉狀態, 即客戶端已經沒有數據要發送了, 但是服務器若要發送數據,客戶端依然要接收。
- 這個狀態還要持續一段時間, 也就是整個
CLOSE-WAIT
狀態持續的時間。
- 客戶端 在接收到服務器的 斷開連接的確認ack報文后,此時
- 客戶端就進入了
FIN-WAIT-2(終止等待2)
狀態,等待服務器發送連接釋放報文。
- 客戶端就進入了
- 服務端收到客戶端發送的
-
第三次揮手
- 服務端發送完
ACK
報文后,在確認數據傳輸完畢后,會發送一條FIN(結束)
的報文到客戶端。 - 由於處於半關閉狀態, 服務器可能又發送可一些數據,假定此時的序列號為 seq = w
FIN = 1
,ack = u + 1
。- 此時, 服務器就進入
LAST-ACK(最后確認)
狀態了。
- 服務端發送完
-
第四次揮手
- 最后, 客戶端收到了服務端的
FIN = 1
的報文后,知道客戶端已經沒有數據需要傳輸了,由客戶端最后再向服務器發送ACK = 1
的確認報文。並ack = w(服務端發送的seq)+1
以及seq = u+2
. - 此時 客戶端進入
TIME-WAIT(時間等待)
狀態。 - 注意,此時TCP 連接還沒有釋放, 必須經過 2 ** MSL(最長報文段壽命) 的時間后, 當前客戶端撤銷相應的TCB后才進入 CLOSED狀態。
- 服務器端只要接收到客戶端發送的確認, 就立即進入CLOSED狀態。
- 綜上所述: 服務器端結束TCP連接的時間要比客戶端早一些。
- 最后, 客戶端收到了服務端的
-
-
思考(一):為什么是 4次揮手?
- 首先肯定是為了保證數據能個完成全部的傳輸過程。
- 當關閉連接時, 當收到對方發送的
FIN
報文是, 僅僅表示對方沒有數據發送給你了。但未必是你發送給對方的數據是否全部發送完畢了,所以你未必可以馬上就關閉SOCKET 套接字。所以你可能需要繼續傳輸數據給對方。數據發送完完畢后再發送一個FIN報文給對方。 所以此時服務端的ACK
報文 和FIN
報文是分開來發送的。
-
思考(二):數據傳輸過程中客戶端突然掛了怎么辦?
- 正常連接時, 客戶端會掛了,如果沒有措施處理這種情況的話, 那么就會出現客戶端和服務端出現長時間空閑掛起。
- 解決辦法就是在服務器端設置保活計時器,每當服務器收到客戶端的消息, 就將計時器復位。計時器的超時時長通常設置為2小時。
- 如果服務器超過2小時沒收到客戶端的消息, 他就發送探測報文段,若發送10個探測報文段, 每個相隔75s,還沒有相應, 就認為客戶端出現故障了, 因而終止該連接。
-
思考(三): 為什么客戶端最后還要等待 2MSL?
-
MSL(Maximun Segment Lifetime)
最長報文壽命 -
1、保證客戶端發送的最后一個ACK報文能夠順利服務器,因此這個報文在數據傳輸過程中可能會丟失
- 站在服務器角度來看,服務器已經發送了
FIN+ACK
報文請求斷開了, 客戶端沒有給我相應,應該是我發送的請求斷開的報文,客戶端沒有接收到, 於是服務器又會重新發送一次,而客戶端就可以再2MSL時間內, 重傳這個報文,接着給出ACK報文后, 會重啟2MSL計時器。
- 站在服務器角度來看,服務器已經發送了
-
2、防止已經失效的連接請求報文段出現在在本連接中。
- 客戶端發送完最后一個確認報文后,在這個2MSL時間中, 就可以是本連接吃的時間內所產生的所有報文段都從網絡中小時。這樣新的連接中不會出現連接的請求報文。
-
3、那么等待2MSL 就一定沒問題了嘛?
- 不,還有一個超時機制, 超時了,即使沒有收到回復也會關閉連接。
-
-
思考(4): SYN(洪流)攻擊(后面有機會再補充)?