
TCP工作在哪一層、為什么需要TCP協(xié)議?
TCP/IP是一個四層的體系結構,主要包括:應用層、傳輸層、網(wǎng)絡層和網(wǎng)絡接口層。
五層協(xié)議的體系結構主要包括:應用層、傳輸層、網(wǎng)絡層,數(shù)據(jù)鏈路層和物理層。
OSI七層協(xié)議模型主要包括是:應用層(Application)、表示層(Presentation)、
會話層(Session)、傳輸層(Transport)、網(wǎng)絡層(Network)、數(shù)據(jù)鏈路層(Data Link)、物理層(Physical)。

發(fā)送端在層與層之間傳輸數(shù)據(jù)時,每經(jīng)過一層時會被打上一個該層所屬的首部信息。反之,接收端在層與層之間傳輸數(shù)據(jù)時,每經(jīng)過一層時會把對應的首部信息去除。

IP 層是不提供可靠性保障的、無狀態(tài)的,它不保證網(wǎng)絡包的交付、不保證網(wǎng)絡包的按序交付、也不保證網(wǎng)絡包中的數(shù)據(jù)的完整性。
如果需要保障網(wǎng)絡數(shù)據(jù)包的可靠性,那么就需要由上層(傳輸層)的 TCP 協(xié)議來負責。
因為 TCP 是一個工作在傳輸層的可靠數(shù)據(jù)傳輸?shù)姆?,它能確保接收端接收的網(wǎng)絡包是無損壞、無間隔、非冗余和按序的。
TCP首部

- 每個TCP段都包含源端和目的端的端口號,用于尋找發(fā)端和收端應用進程。這兩個值加上IP首部中的源端IP地址和目的端IP地址唯一確定一個TCP連接。
- 序列號用來標識從TCP發(fā)端向TCP收端發(fā)送的數(shù)據(jù)字節(jié)流,它表示在這個報文段中的的第一個數(shù)據(jù)字節(jié)。如果將字節(jié)流看作在兩個應用程序間的單向流動,則TCP用序列號對每個字節(jié)進行計數(shù)。序列號是32 bit的無符號數(shù),序列號到達232-1后又從0開始。用來解決網(wǎng)絡包亂序問題。
- 確認應答號包含發(fā)送確認的一端所期望收到的下一個序號。因此,確認序號應當是上次已成功收到數(shù)據(jù)字節(jié)序號加1. 用來解決不丟包的問題
- 標志比特:
ACK:該位為 1 時,「確認應答」的字段變?yōu)橛行?,TCP 規(guī)定除了最初建立連接時的 SYN 包之外該位必須設置為 1 。
RST:該位為 1 時,表示 TCP 連接中出現(xiàn)異常必須強制斷開連接。
SYN:該位為 1 時,表示希望建立連接,并在其「序列號」的字段進行序列號初始值的設定。
FIN:該位為 1 時,表示今后不會再有數(shù)據(jù)發(fā)送,希望斷開連接。當通信結束希望斷開連接時,通信雙方的主機之間就可以相互交換 FIN 位為 1 的 TCP 段。
使用WireShark抓包分析三次握手


TCP 建立連接為什么需要三次握手
針對這個問題,首先我們需要知道什么是連接,只有知道連接的定義,我們才能去嘗試回答為什么 TCP 建立連接需要三次握手。
什么是TCP連接?
用于保證可靠性和流量控制維護的某些狀態(tài)信息,這些信息的組合,包括Socket、序列號和窗口大小稱為連接。
所以,重要的是為什么三次握手才可以初始化Socket、序列號和窗口大小并建立 TCP 連接。
接下來以三個方面分析三次握手的原因:
- 三次握手才可以阻止重復歷史連接的初始化(主要原因)
- 三次握手才可以同步雙方的初始序列號
-
三次握手才可以避免資源浪費
如果客戶端的 SYN 阻塞了,重復發(fā)送多次 SYN 報文,那么服務器在收到請求后就會建立多個冗余的無效鏈接,造成不必要的資源浪費。

TCP 協(xié)議的通信雙方, 都必須維護一個「序列號」, 序列號是可靠傳輸?shù)囊粋€關鍵因素,它的作用:
接收方可以去除重復的數(shù)據(jù);
接收方可以根據(jù)數(shù)據(jù)包的序列號按序接收;
可以標識發(fā)送出去的數(shù)據(jù)包中, 哪些是已經(jīng)被對方收到的;
SYN攻擊

我們都知道 TCP 連接建立是需要三次握手,假設攻擊者短時間偽造不同 IP 地址的 SYN 報文,服務端每接收到一個 SYN 報文,就進入SYN_RCVD 狀態(tài),但服務端發(fā)送出去的 ACK + SYN 報文,無法得到未知 IP 主機的 ACK 應答,久而久之就會占滿服務端的SYN 接收隊列(未連接隊列),使得服務器不能為正常用戶服務。


TCP連接斷開

為什么 TIME_WAIT 等待的時間是 2MSL?
- 為了保證客戶端最后一次揮手的報文能夠到達服務器,如果第四次揮手的報文段丟失了,服務器會超時重傳這個第三次揮手的報文段,
所以客戶端不是直接進入CLOSED,而是要保持TIME_WAIT(等待2MSL就是TIME_WAIT)就起到作用了,
當再次收到服務器的超時重傳的斷開連接的第三次揮手的請求的時候,
客戶端會繼續(xù)給服務器發(fā)送一個第四次揮手的報文,能夠保證對方(服務器)收到客戶端的回應報文,最后客戶端和服務器正確的關閉連接。 - 如果Client(客戶端)直接CLOSED(關閉),然后又再向Server(服務器端)發(fā)起一個新連接,
我們不能保證這個新連接與剛關閉的連接的端口號是不同的。也就是說有可能新連接和老連接的端口號是相同的。
一般來說不會發(fā)生什么問題,但是還是有特殊情況出現(xiàn):假設新連接和已經(jīng)關閉的老連接端口號是一樣的,
如果前一次連接的某些數(shù)據(jù)仍然滯留在網(wǎng)絡中,這些延遲數(shù)據(jù)在建立新連接之后才到達Server,
由于新連接和老連接的端口號是一樣的,于是,TCP協(xié)議就認為那個延遲的數(shù)據(jù)是屬于新連接的,這樣就和真正的新連接的數(shù)據(jù)包發(fā)生混淆了。
所以TCP連接還要在TIME_WAIT狀態(tài)等待2倍MSL,這樣可以保證本次連接的所有數(shù)據(jù)都從網(wǎng)絡中消失。

超時與重傳
超時重傳 :在發(fā)送數(shù)據(jù)時,設定一個定時器,當超過指定的時間后,沒有收到對方的 ACK 確認應答報文,就會重發(fā)該數(shù)據(jù)
TCP 會在以下兩種情況發(fā)生超時重傳:
- 數(shù)據(jù)包丟失
-
確認應答丟失
重傳超時時間RTO計算
TCP超時與重傳中最重要的部分就是對一個給定連接的往返時間(RTT)的測量。由于路由器和網(wǎng)絡流量均會變化,因此我們認為這個時間可能經(jīng)常會發(fā)生變化,TCP應該跟蹤這些變化并相應地改變其超時時間。
滑動窗口

win這個字段是接收端告訴發(fā)送端自己還有多少緩沖區(qū)可以接收數(shù)據(jù)。于是發(fā)送端就可以根據(jù)這個接收端的處理能力來發(fā)送數(shù)據(jù),而不會導致接收端處理不過來。起到流量控制的作用

可用窗口的大小為 0 時,表明可用窗口耗盡,在沒收到 ACK 確認之前是無法繼續(xù)發(fā)送數(shù)據(jù)了。
擁塞控制
前面的流量控制是避免「發(fā)送方」的數(shù)據(jù)填滿「接收方」的緩存,但我們并不知道當時的網(wǎng)絡狀況是怎樣的,在網(wǎng)絡出現(xiàn)擁堵時,如果繼續(xù)發(fā)送大量數(shù)據(jù)包,可能會導致數(shù)據(jù)包時延、丟失等,這時 TCP 就會重傳數(shù)據(jù),但是一重傳就會導致網(wǎng)絡的負擔更重,于是會導致更大的延遲以及更多的丟包,這個情況就會進入惡性循環(huán)被不斷地放大....
每一個 TCP 連接都會維護一個擁塞控制窗口(cwnd),它決定了發(fā)送方同時能向接收方發(fā)送多少數(shù)據(jù),其作用主要有兩個:
- 防止發(fā)送方向接收方發(fā)送了太多數(shù)據(jù),導致接收方無法處理;
- 防止 TCP 連接的任意一方向網(wǎng)絡中發(fā)送大量數(shù)據(jù),導致網(wǎng)絡擁塞崩潰;
使用 TCP 慢啟動時,發(fā)送方每收到一個響應方的 ACK 消息,擁塞窗口大小就會加一。當擁塞窗口大小大于慢啟動閾值時,就會使用擁塞避免算法:
線性增長:每經(jīng)過一個往返時間 RTT,擁塞窗口大小會加一;
積式減少:當發(fā)送方發(fā)送的數(shù)據(jù)包丟包時,慢啟動閾值會設置為擁塞窗口大小的一半;
慢啟動為發(fā)送方的TCP增加了另一個窗口:擁塞窗口(congestion window),記為cwnd。當與另一個網(wǎng)絡的主機建立TCP連接時,擁塞窗口被初始化為1個報文段(即另一端通告的報文段大?。?。每收到一個ACK,擁塞窗口就增加一個報文段(cwnd以字節(jié)為單位,但是慢啟動以報文段大小為單位進行增加)。發(fā)送方取擁塞窗口與通告窗口中的最小值作為發(fā)送上限。擁塞窗口是發(fā)送方使用的流量控制,而通告窗口則是接收方使用的流量控制。


當cwnd超過一定的閥值,就會啟動擁塞避免算法.

網(wǎng)絡就會慢慢進入了擁塞的狀況了,于是就會出現(xiàn)丟包現(xiàn)象,這時就需要對丟失的數(shù)據(jù)包進行重傳。
當觸發(fā)了重傳機制,也就進入了「擁塞發(fā)生算法」。
當網(wǎng)絡出現(xiàn)擁塞,也就是會發(fā)生數(shù)據(jù)包重傳,重傳機制主要有兩種:
- 超時重傳
-
快速重傳
當發(fā)生了「超時重傳」,則就會使用擁塞發(fā)生算法。
這個時候,ssthresh 和 cwnd 的值會發(fā)生變化:
ssthresh 設為 cwnd/2,
cwnd 重置為 1
超時重傳.png
當接收方發(fā)現(xiàn)丟了一個中間包的時候,發(fā)送三次前一個包的 ACK,于是發(fā)送端就會快速地重傳,不必等待超時再重傳。
cwnd = cwnd/2 ,也就是設置為原來的一半;
ssthresh = cwnd;



