TCP深入解析

TCP/IP深入剖析

在瞭解TCP/IP和UDP/IP之前,我個人認爲大家應該先知道OSI七層網絡模型的知識,可能科班出身的在大學學習過這些知識,我在這裏也不深入了,簡單介紹一下,就當爲TCP/IP做一個鋪墊.

OSI七層網絡模型:

OSI(Open System Interconnect),即開放式系統互聯。 一般都叫OSI參考模型,是ISO(國際標準化組織)組織在1985年研究的網絡互連模型。 ISO爲了更好的使網絡應用更爲普及,推出了OSI參考模型。其含義就是推薦所有公司使用這個規範來控制網絡。這樣所有公司都有相同的規範,就能互聯了。

  1. OSI七層網絡模型指的是那七層呢?
    從上到下依次爲應用層,表示層,會話層,傳輸層,網絡層,數據鏈路層,物理層
  2. 那通常說的TCP/IP五層模型又是啥呢?
    其實只是參考OSI模型而已,說白了就是五層模型中把OSI的應用層,表示層以及會話層統稱爲了應用層,自然而然的五層模型就是指:應用層,傳輸層,網絡層,數據鏈路層,物理層
    來一些圖可能更好理解一點:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

每一層都代表什麼呢?

應用層
OSI參考模型中最靠近用戶的一層,是爲計算機用戶提供應用接口,也爲用戶直接提供各種網絡服務。我們常見應用層的網絡服務協議有:HTTP,HTTPS,FTP,POP3、SMTP等。

表示層
表示層提供各種用於應用層數據的編碼和轉換功能,確保一個系統的應用層發送的數據能被另一個系統的應用層識別。如果必要,該層可提供一種標準表示形式,用於將計算機內部的多種數據格式轉換成通信中採用的標準表示形式。數據壓縮和加密也是表示層可提供的轉換功能之一。
會話層
會話層就是負責建立、管理和終止表示層實體之間的通信會話。該層的通信由不同設備中的應用程序之間的服務請求和響應組成。
傳輸層
傳輸層建立了主機端到端的鏈接,傳輸層的作用是爲上層協議提供端到端的可靠和透明的數據傳輸服務,包括處理差錯控制和流量控制等問題。該層向高層屏蔽了下層數據通信的細節,使高層用戶看到的只是在兩個傳輸實體間的一條主機到主機的、可由用戶控制和設定的、可靠的數據通路。我們通常說的,TCP UDP就是在這一層。端口號既是這裏的“端”。
網絡層
本層通過IP尋址來建立兩個節點之間的連接,爲源端的運輸層送來的分組,選擇合適的路由和交換節點,正確無誤地按照地址傳送給目的端的運輸層。就是通常說的IP層。這一層就是我們經常說的IP協議層。IP協議是Internet的基礎。
數據鏈路層
將比特組合成字節,再將字節組合成幀,使用鏈路層地址 (以太網使用MAC地址)來訪問介質,並進行差錯檢測。 數據鏈路層又分爲2個子層:邏輯鏈路控制子層(LLC)和媒體訪問控制子層(MAC)。MAC子層處理CSMA/CD算法、數據出錯校驗、成幀等;LLC子層定義了一些字段使上次協議能共享數據鏈路層。 在實際使用中,LLC子層並非必需的。
物理層
實際最終信號的傳輸是通過物理層實現的。通過物理介質傳輸比特流。規定了電平、速度和電纜針腳。常用設備有(各種物理設備)集線器、中繼器、調制解調器、網線、雙絞線、同軸電纜。這些都是物理層的傳輸介質。

TCP/IP通信原理

上邊簡單介紹了一下網絡模型的概念,但是在傳輸層中的TCP是怎麼通信的呢?我們都會知道三次握手和四次揮手,但是這兩次交流到底是怎麼回事呢?端到端又是如何傳輸的呢?傳輸的數據又是什麼樣子呢?
在講解傳輸層通信之前,需要先介紹另一個東西,那就是報文段,報文段是指TCP/IP協議網絡傳輸過程中,起着路由導航,查詢各個網絡路由網段,IP地址,交換協議等IP數據包。報文段充當整個TCP/IP協議數據包的導航路由功能.TCP提供的是一種面向連接的可靠的字節流服務,TCP提供可靠性的一種重要的方式就是MSS。通過MSS,應用數據被分割成TCP認爲最適合發送的數據塊,由TCP傳遞給IP的信息單位稱爲報文段或段(segment)。代表一個TCP socket的結構體struct tcp_sock中有多個成員用於確定應用數據被分割成最大爲多大的數據塊較爲合適(最大報文段長度MSS)。跟最大報文段長度最爲相關的一個參數是網絡設備接口的MTU,以太網的MTU是1500,基本IP首部長度爲20,TCP首部是20,所以MSS的值可達1460(MSS不包括協議首部,只包含應用數據)。咱們從外到內的扒一扒,心急吃不了熱豆腐嘛!

用幾張圖來一層一層的扒,先研究下全身(報文段):

在這裏插入圖片描述

再看看臉(IP首部):

這裏以IPV4來說,6不在討論範圍哈.
在這裏插入圖片描述
IP首部不包含上圖中的數據部分,數據部分其實就是TCP的內容了,咱們一會再說,先說說IP首部,由上圖可以看出來,IP首部包含有20個固定字節,也就是480個比特位,圖是爲了好識別才這麼畫的,其實從上到下你可以理解成連續的,只不過分了一下段而已,那下邊我就從頭到尾依次介紹一下他們具體是幹什麼的:
版本:
長度是4個比特位,指IP協議的版本。通信雙方使用IP協議的版本必須一致,比如你使用的是IPV4這裏就是4
首部長度
長度是4個比特位,顧名思義,這個字段就是標識了IP數據報的首部長度。該字段以4字節爲單位,可以表示的最大的數是”1111”,也就是十進制數15,所以IP首部長度最大爲60字節(15*4=60)。由於IP首部固定長度爲20字節,所以該字段的最小值爲”0101
區分服務
佔8個比特位。有3位優先權字段已經棄用,還有4位TOS字段和1位保留字段(這個保留字段必須置爲0)。4位TOS字段分別代表最小延時、最大吞吐量、最高可靠性、最低成本。這四者相互衝突,只能選擇一個。
總長度
佔16個比特位,表示IP數據報的總長度(包括數據部分)。單位爲字節,所以數據報的最大長度爲65536字節(2^16-1)。
在這裏補充一個知識:最大傳輸單元MTU。表示某一層上面可以通過的最大的數據包的大小,所以IP數據報的總長度不能超過下面數據鏈路層的MTU值。
爲了不使IP數據報的傳輸速率降低,規定所以主機和路由器必須能夠處理的IP數據報長度不得小於576字節。當數據報長度超過網絡所容許的最大傳輸單元時,就要把過長的數據報進程分片,這時數據報首部中的總長度不是指沒有分片前的數據報長度,而是指分片後每一個分片數據報的長度。
標識
佔16個比特位,IP軟件在存儲器中維持一個計數器,每產生一個數據報計數器就加一,並將這個值賦給標識字段。當數據報長度超過網絡的MTU要進行分片時這個標識字段的值就會複製到所有的數據報片的標識字段中。爲了之後重新組裝數據的時候可以分辨哪些數據報之前屬於一個數據報的。
標誌
佔3個比特位。標誌雖然佔了三位,但目前只有兩位有意義
MF:在最低位,MF=1表示後面還有分片的數據報,MF=0表示這已經是所有數據報片中的最後一個了
DF:在中間的一位,DF=1表示不允許分片,DF=0表示允許分片
片偏移
佔13個比特位。該字段表示,被分片的數據報,每一個數據報片在原分組的相對位置。也就是說相對於用戶數據字段的起點該片從何處開始。
片偏移以8個字節爲單位所以每個分片的長度一定是8字節的整數倍
生存時間
佔8個比特位,這個字段也就是我們常說的TTL,表示數據報在網絡中的壽命,目的是爲了防止數據報在傳送過程中無限制的在因特網中兜圈子而白白浪費網絡資源。
TTL的單位是跳數,路由器在轉發這個數據報之前就將該數據報的TTL減一,當數據報的TTL被減到0時,就丟棄這個數據報。
協議
佔8個比特位。協議字段指出此數據報攜帶的是哪種協議,這樣就可以使目的主機的網絡層知道應該將數據部分上交給哪個傳輸層協議處理。
具體數值與協議的對應如下表:

協議名 協議字段值
ICMP 1
IGMP 2
TCP 6
EGP 8
IGP 9
UDP 17
IPV6 41
OSPF 89

首部檢驗和
佔16個比特位,這個字段是爲了幫助路由器檢驗收到的IP數據報中的比特錯誤。需要注意的是,這個字段只檢驗數據報的首部,不包括數據部分。數據報每經過一個路由器,路由器都要重新計算一下首部檢驗和。
來看看IP數據報是如何檢驗的:

  1. 在發送方,先把IP數據報首部劃分爲許多的16位字的序列,並把檢驗和字段置零。
  2. 在用反碼算數運算把所有16位字相加後,將得到的和的反碼寫進檢驗和字段。
  3. 接收方收到數據報之後,將首部的所有16位字在使用反碼算數運算相加一次,將得到的和取反碼,即得出接收方檢驗和的計算結果。
  4. 我們根據接收方檢驗和結果判斷,如果結果爲0,表示此數據報有效,不爲0就丟棄該數據報。

源IP地址
佔32個比特位,表示發送方主機的IP地址
目的IP地址
佔32個比特位,表示接收方主機的IP地址
可變部分
IP首部的可變部分就是一個選項字段。此字段長度可變,從1字節~40字節不等。最後用全0的填充字段補齊爲4字節的整數倍
注:IPV6不在採用此字段
數據
數據字段就是要交付給目的地的傳輸層報文段(TCP/UDP等),也可以承載其他類型的數據(ICMP報文段等)

最後慢慢研究身材(IP數據部分):

IP數據部分其實就是TCP的報文了,也是咱們這裏說的重點了,也就是IP首部介紹的時候的那個數據
老樣子,先上圖:
在這裏插入圖片描述
如果IP報文段首部的協議是TCP,那麼自然IP數據部分也就是TCP的內容,如下:
在這裏插入圖片描述

1、源端口號
佔16位,標識發送主機的端口或進程,一個TCP報文必須包含源端口號,要讓接收主機知道該向哪發送確認報文
2、目的端口號
佔16位,標識目的主機的端口或進程
3、序號
佔32位,即4個字節。序號範圍是0~(2^32-1), 當序號增加到2^32-1後,下一個序號又會變成0。因爲TCP是面向字節流的,在一個TCP連接中的每一個字節都按順序編號。整個要傳送的字節流的起始序號必須在連接建立時設置。首部中的序號字段則指的是本報文段所發送的數據的第一個字節的序號。
4、確認序號
同樣的佔4個字節,標識了期望收到對方下一個報文段的第一個數據字節的序號。
注:若確認序號=N,表明到序號N-1爲止的所有數據都確認收到
5、首部長度
佔4位。這個字段指出TCP報文段的數據起始處距離TCP報文段的起始處有多遠。也就是TCP報文段首部的長度。
6、保留
佔6位,保留爲今後用,目前都置爲0
7、六個標誌位

  • URG:緊急標誌位。當URG=1時,表明緊急指針字段(後面介紹)有效,它告訴操作系統報文段中有緊急數據應該被儘快傳送

  • ACK:確認標誌位。僅當ACK=1時該字段纔有效。TCP規定在連接建立後所有傳送的報文段都必須把ACK置爲1

  • PSH:推送標誌位。當兩個應用進程進行交互式的通信時,有時在一端的應用進程希望在鍵入一個命令後立即就能夠收到對方的響應。在這種情況下,發送方TCP就可以將PSH字段置1 ,並立即創建一個報文段發送出去,接收方收到 PSH = 1的報文段,就儘快地交付給接收應用進程,而不再等到整個緩存都填滿後再向上交付。

  • RST:復位標誌位。當RST=1時,表明TCP連接中出現了嚴重差錯必須釋放連接,然後在重新建立運輸連接。RST置爲1還可以用來拒絕一個非法的報文段或拒絕打開一個連接。

  • SYN:同步標誌位。在連接建立時用來同步序號。當SYN=1而ASK=0時表明這是一個連接請求報文段。如果對方同意建立連接,就可以在響應報文段中使用SYN=1和ACK=1。

  • FIN:終止標誌位。用來釋放一個連接,當FIN=1時,表明此報文段發送方的數據已經發送完畢,並要求釋放連接。
    8、窗口
    佔16位。窗口值是0~(2^16-1)之間的整數。
    窗口指的是發送本報文段的一方的接收窗口,也就是自己接受緩衝區的大小。窗口值告訴對方,從本報文段首部中的確認號算起,接收方目前允許對方發送的數據量。窗口值作爲接收方讓發送方設置其發送窗口的依據。
    9、檢驗和
    佔16位。和IP數據報不同的是,TCP報文段檢驗的範圍包括首部和數據兩部分(IP數據報只檢驗首部部分),但是檢驗方法類似。

  1. 在發送方,首先把全零放入檢驗和字段
  2. 把僞首部以及TCP數據報看成是由許多16位字的字串連接起來。若TCP報文段的數據部分不是偶數個字節,則要填入一個全零字節(但此字節不發送)
  3. 然後按二進制反碼計算出這些16位字的和,將結果的二進制反碼寫入檢驗和字段併發送
  4. 在接受方,把收到的TCP報文連同僞首部一起按二進制反碼求出這些16位字德和。當無差錯時結果爲1,若結果爲0,就表示有差錯,接收方就丟棄這個報文段

在這裏說一下僞首部的概念:僞首部有12個字節,分爲5個字段。
第一字段和第二字段分別爲源IP地址和目的IP地址。
第三字段是全零
第四字段是IP首部中的協議字段的值
第五字段是TCP數據報的長度
10、緊急指針
佔16位。緊急指針只在URG=1時有效,標識了本報文段中緊急數據的字節數,指出來緊急數據末尾在報文段中的位置
注:當窗口爲0時,也可以發送緊急數據。
11、選項
也是一個可變長字段最大可達40字節,當沒有使用選項時,TCP的首部長度就是20字節。

如果IP報文段首部的協議是UDP,那麼自然IP數據部分也就是UDP的內容,UDP相對來說就比較簡單了,如下:
在這裏插入圖片描述
1、源端口號
佔16位。標識源主機的端口或進程,同TCP。
2、目的端口號
佔16位。標識要發送個目的主機的哪個端口或進程
3、首部長度
佔16位。標識UDP整個數據報的長度(包括首部和數據)。最小值爲8(僅有首部)
4、檢驗和
佔16位。檢測UDP用戶數據報在傳輸中是否有錯,有錯就丟掉。檢測方式同TCP一樣,檢驗範圍也是包括首部和數據。

UDP與TCP的區別
UDP:
面向非鏈接,即發送數據之前不需要建立連接
不維護鏈接狀態,支持同時向多個客戶端傳輸相同消息
數據包報頭只有8個字節,額外開銷較小
吞吐量只受限於數據生成速率,傳輸速率以及機器性能
盡最大努力交付,不保證可靠交付,不需要維持複雜的鏈接狀態表
UDP是面向報文的,不對應用程序提交的報文信息進行拆分或合併,所以報文大小由應用程序解決和優化, UDP沒有擁塞控制,因此網絡出現擁塞不會使源主機的發送速率降低(對實時應用很有用,如IP電話,實時視頻會議等)
UDP支持一對一,一對多,多對一和多對多的交互通信
UDP則是不可靠信道
TCP:
面向鏈接,三次握手,四次揮手
TCP提供可靠的服務,通過TCP連接傳送的數據,無差錯,不丟失,不重複,且按序到達
TCP面向字節流,實際上是TCP把數據看成一連串無結構的字節流
每一條TCP連接只能是點到點的,TCP速度比UDP慢
TCP屬於重量級,UDP屬於輕量級,TCP報頭20個字節UDP報頭8個字節
TCP的邏輯通信信道是全雙工的可靠信道

單工,半雙工,全雙工
單工:我跟你說話,你不能跟我說.
半雙工:我跟你說話,你只能等我說完了你才能跟我說.
全雙工:我跟你說話,你不用等我說完就可以中途插嘴跟我說話!

好了,到這裏報文段基本算是結束了,下面我們就結合通信來說,這些比特位爲什麼存在,有啥作用?

三次握手

在這裏插入圖片描述
客戶端與服務端想要通信,就需要發送三個數據包來最終確定建立一個連接.就像是:


我:

  1. 約不約?
  2. 然後滿臉期待.

妹子:

  1. 聽到我問她了約不約了.
  2. 然後說"約"
  3. 然後心裏想着"算你識相,還知道主動約老孃!"

我:

  1. 聽到並且確認妹子同意了
  2. 說"那走吧!"
  3. 然後屁顛屁顛牽着妹子手進行下一步了!

1. 那這三次交流到底是怎麼完成的呢?
第一次握手(我):
  客戶端向服務端發送一個SYN=1(位數爲1),seq=x(同步序列編號,隨機產生一個)到服務端(也就是約不約?),然後客戶端進入SYN_SENT(同步發送)狀態,然後等待服務端確認.當SYN=1而ASK=0時表明這是一個連接請求報文段。如果對方同意建立連接,就可以在響應報文段中使用SYN=1和ACK=1,TCP規定SYN=1時不能攜帶數據,但要消耗一個序號,因此聲明自己的序號是 seq=x
第二次握手(妹子):
  當服務端收到客戶端的SYN包之後,就必須確認客戶端的SYN,也就是(ack=x+1)表示我收到這個消息了,同時自己也發送一個SYN包(SYN=1,seq=y,ACK=1,ack=x+1)給客戶端,告訴客戶端我收到你發給我的消息了,同時自己進入一個SYN_RECV狀態(同步收到)
第三次握手(我)
  當客戶端收到服務端的"約"(SYN+ACK包)並且驗證ack=x+1,seq=x+1以後,客戶端就明白服務端知道了,也就是同意建立連接了,然後客戶端就需要再告訴服務端一聲,我準備給你數據了,也就是向服務端發送確認包ACK( ACK=1, seq=x+1, ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手.
2. 說完三次握手問題也就隨之而來了,爲什麼是三次握手不是兩次呢?
   不是兩次是三次的主要原因其實是爲了防止已失效的請求報文段突然又傳送到服務端的情況.這樣會造成連接異常.
假設有這麼一種情況:
  當客戶端發送SYN包給服務端時,由於網絡問題,造成了數據包延遲,請求報文段在網絡節點中滯留了,也就是第一次握手被無限延長了,妹子短時間內沒聽到,後來客戶端又問了一次,也就是又發送一次SYN包給服務端,然後服務端回覆了,之後建立連接,但是第一次的SYN包還在網絡節點裏,但是並沒有消失,等網絡通暢了,這個SYN包又被服務端接收了,然後服務端又回覆了一個消息給客戶端,如果客戶端不確認這個請求報文段,那麼就直接建立連接了,但是此時的客戶端已經走遠了,完全不知道妹子隔了那麼久突然跟他說約,客戶端聽不到了,但是妹子還一直等着客戶端回覆呢,這就造成了服務端一直等待確認的情況,如果次數多了,對服務端是一個很大的BUG,會造成很多資源浪費.所以纔有了第三次握手的確認過程!
3. 三次握手引起的DOS/SYN攻擊
   什麼是DOS或者SYN攻擊呢,其實就是根據三次握手的漏洞造成的,原理是什麼呢?其實也就是上邊說的那種情況,客戶端一直向服務端發送SYN包,然後服務端回覆並進入SYN_RECV狀態(同步收到),此時客戶端不再進行第三次握手,並且頻繁的發送第一次握手給服務端,那麼服務端會一直接收SYN包並回復,但是沒有了後續的事情,所以服務端久而久之就會崩潰,當然這是單機的DOS攻擊,像分佈式的DDOS攻擊不多贅述了!

四次揮手

在這裏插入圖片描述
客戶端與服務端想要終止通信,就需要四次通信了.就像是:


我:

  1. 我們分手吧,你馬上給我搬出去,我不想再看到你!
  2. 然後氣憤的等着妹子答覆!

妹子:

  1. 分手就分手!老孃早看你不順眼了,我現在就收拾完東西走人!哼!
  2. 然後妹子開始收拾東西,我繼續等着

妹子:

  1. 收拾完了
  2. 衝我吼到"永不相見!"

我:

  1. 趕緊滾!,然後妹子走了,我又單身了!

1. 那這四次交流到底是怎麼完成的呢?
第一次揮手(我):
  我跟妹子要分手,是我主動提出的,也沒啥好說的,所以客戶端數據發送完了沒數據再發送了,所以主動要求關閉此次長連接,然後給服務端發送一個釋放連接的報文段,而這個報文段首部是FIN=1,序列號是seq=u(u其實就是前面傳送過來的數據的最後一個字節序號+1,TCP規定,及時報文不帶數據也必須要消耗一個序列號,所以這裏必須有seq),等客戶端發送完成,也就是我說完分手以後就等着妹子答覆了,此時進入了終止連接等待狀態1(FIN-WAIT-1).
第二次揮手(妹子):
  妹子聽到我要跟她分手,很氣憤,所以告訴我分就分,也就是服務端接收到客戶端發送過來的FIN報文段以後隨即給客戶端發送確認ACK報文段,也就是ACK=1,ack=u+1,並且還有自己的序列號seq=v(分手就分手!老孃早看你不順眼了,我現在就收拾完東西走人!哼!),然後服務端進入了關閉等待狀態(CLOSE-WAIT,也就是開始收拾東西,發送沒有發送完的數據),服務端通知完客戶端,客戶端這邊針對服務端的連接就釋放了,這時候服務端處於半關閉狀態,即客戶端已經沒有數據要發送了,但是服務器可能還要發送數據,客戶端依然需要接受數據,這個發送數據的狀態還是要持續一段時間,這也就是整個CLOSE-WAIT狀態需要持續等待的時間.然後就是我聽到妹子說要收拾完東西走,那我就等着她收拾完讓她走人,也就是客戶端收到服務端的確認ACK報文段之後,客戶端進入終止連接等待狀態2(FIN-WAIT-2),此時客戶端等待服務端發送釋放連接的報文的同時,還要繼續接收服務端未發送完的數據.也就是我不僅要等着她走還要看着她收拾完東西.
第三次揮手(妹子)
  妹子收拾完了,然後跟我說永不相見.也就對應着服務端向客戶端發送數據徹底完畢(東西收拾完準備撤了),此時服務端想客戶端發送釋放連接的FIN報文段(FIN=1,ack=u+1),由於服務端處於半關閉狀態,這個期間還發送給客戶端數據,所以此時的序列號已經不是之前的連續序列號了,假設此時發送的關閉連接報文段序列號爲seq=w,那麼報文段發送過去之後,服務端自然就進入了最後等待確認釋放的狀態,也就是等着客戶端確認可以斷開了.(也就是等着我說"趕緊滾")
第四次揮手(我)
  等我看到妹子收拾完了,我就說趕緊滾!,然後妹子走了,我又單身了!也就對應着服務端發送給客戶端FIN報文段之後,客戶端接收到了服務端釋放連接的確認報文段,自然要給服務端迴應說ok,所以客戶端需要向服務端發送最終的斷開連接確認ACK報文段(ACK=1,ack=w+1,seq=u+1),此時,客戶端就確認完成了,自動進入報文壽命終結的狀態,也就是等待此次報文失效的那一段時間(TIME-WAIT),需要搞明白的是,客戶端發送ACK確認報文以後並不是直接就釋放連接了,而是需要等待2MSL的時間之後,客戶端纔會進入關閉狀態,與此同時,服務端接收到客戶端的確認報文之後會直接進入關閉狀態.

2. 什麼是2MSL?
  MSL是Maximum Segment Lifetime英文的縮寫,中文可以譯爲“報文最大生存時間”,他是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。因爲tcp報文(segment)是ip數據報(datagram)的數據部分,具體稱謂請參見《數據在網絡各層中的稱呼》一文,而ip頭中有一個TTL域,TTL是time to live的縮寫,中文可以譯爲“生存時間”,這個生存時間是由源主機設置初始值但不是存的具體時間,而是存儲了一個ip數據報可以經過的最大路由數,每經過一個處理他的路由器此值就減1,當此值爲0則數據報將被丟棄,同時發送ICMP報文通知源主機。RFC 793中規定MSL爲2分鐘,實際應用中常用的是30秒,1分鐘和2分鐘等。
  2MSL即兩倍的MSL,TCP的TIME_WAIT狀態也稱爲2MSL等待狀態,當TCP的一端發起主動關閉,在發出最後一個ACK包後,即第3次握手完成後發送了第四次握手的ACK包後就進入了TIME_WAIT狀態,必須在此狀態上停留兩倍的MSL時間,等待2MSL時間主要目的是怕最後一個ACK包對方沒收到,那麼對方在超時後將重發第三次握手的FIN包,主動關閉端接到重發的FIN包後可以再發一個ACK應答包。在TIME_WAIT狀態時兩端的端口不能使用,要等到2MSL時間結束纔可繼續使用。當連接處於2MSL等待階段時任何遲到的報文段都將被丟棄。不過在實際應用中可以通過設置SO_REUSEADDR選項達到不必等待2MSL時間結束再使用此端口。
TTL與MSL是有關係的但不是簡單的相等的關係,MSL>=TTL

3. 如果已經建立了連接,但是客戶端突然出現故障了怎麼辦?
  TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設置爲2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉連接。

TCP如何維持數據傳輸有序性的?

RTT: 客戶端從發送一個FIN數據包到服務端,服務端收到包併發送ACK確認包給客戶端,一直到客戶端收到ACK確認包所花費的時間.
RTO: 重傳時間間隔, 客戶端在發送一個數據包給服務端的時候會開啓一個重傳定時器, 而這個定時器的時間是通過算法算出來的,它是基於RTT計算得到的,並不是固定數據,在客戶端收到服務端的ACK確認包之後,會讓這個定時器失效,如果定時器時間,也就是超時時間到了都沒有收到ACK包,那麼就開始重新發送.關於這個時間怎麼算不過多描述,如果有興趣可以參考以下兩篇博文:

  1. TCP中RTT的測量和RTO的計算
  2. TCP協議中RTO的計算

TCP的滑動窗口
我們都知道TCP是通過數據包的方式發送數據的,是一段一段的去發送的,而不是整個發送, 因爲每段發送的順序不固定,所以爲了保證TCP的可靠傳輸就需要用到滑動窗口和重傳機制!下面來詳細介紹一下:
TCP會利用滑動窗口來做流量控制以及亂序後的重新排序, 用來保證TCP的可靠性和流控特性,可靠性可能好理解一點,但是流控是什麼,流控其實就是流量控制,也就是數據流的大小控制,上邊介紹的TCP報文段圖中有一個窗口,而這個窗口就是服務端告訴客戶端我還可以接受多少數據的指標,這樣客戶端就可以根據服務端給出的數據大小來處理髮送的數據,也就可以避免服務端數據處理不過來的情況,這也就是TCP的流量控制模式,其實這就是滑動窗口實現的基石之一.

先來兩張圖:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

相信看圖大家已經很明白了,那就是滑動窗口是發生在TCP數據緩衝區中的,而它是怎麼滑的呢?其實看懂第二個圖以後基本也就明白了,大家可能看的有點懵,圖描述的可能有點偏差,但是意思是可以表示的,概念差不多,下面我來詳細介紹一下:

客戶端緩衝區:

  1. lastByteAcked:
    客戶端連續收到ACK確認包後的最大字節位置
  2. lastByteSent
    客戶端已發送但是還未收到ACK確認包的最後一個字節的位置
  3. lastByteWritter
    指客戶端已寫完的最後一個字節的位置,也就是send方法寫入的數據
  4. 發送緩衝區分佈:
    (1):被服務端確認過的數據區
    (2):客戶端已發送未被服務端確認的區域,也就是未收到ACK包的數據區,發送中的狀態
    (3):客戶端已寫入但是未發送的數據區
    (4):客戶端發送緩衝區還能繼續寫入的數據區

服務端緩衝區:

  1. lastByteRead:
    指上層應用已經讀完的最後一個字節的位置,也就是recv方法正在讀的最後一個字節,同時也是服務端給客戶端發送過ACK包的最後一個字節位置
  2. nextByteExpected
    指向的是服務端已經接收到數據包正在處理還沒來的及回覆確認包的字節位置
  3. lastByteRcvd
    指向的是服務端已經接收到數據包最後一個字節的位置,而之前空白的區域也就是還沒接收到的數據部分
  4. 接收緩衝區分佈:
    (5):服務端處理好的數據區,也就是已經發送過ACK確認包之後的數據區
    (6):服務端接收到正在處理還沒有發送ACK確認包的數據區
    (7):客戶端已發送,但是服務端還沒接收到的數據區
    (8):服務端接收到的最大字節之前的數據區(此處包含6和7,可以理解爲8區=6區+7區)
    (9):服務端還能接收的數據區,(5)其實也算是這種數據區 ,此處大小計算方式爲:
    advertisedWindow = MaxRcvBuffer-(lastByteRcvd-lastByteRead)
    還能接收的數據量=緩衝區大小-(正在接收的數據量),而對應的發送緩衝區還能發送多少的計算方式如下:
    effectiveWindow=advertisedWindow -(lastByteSent-lastByteAcked)
    還能發送的數據量=還能接收的數據量-(已發送還未確認的數據量)

怎麼滑的?
好了,該說的基本都說完了,那咱們繼續說怎麼滑這個問題,老樣子,先上圖:

在這裏插入圖片描述
畫這玩意簡直太噁心了,看着有點亂,請見諒,看了我的介紹估計也就用不上這個圖了,腦補一下好了,gif畫起來更噁心,實在是蛋疼!

圖中的方形數字表示發送緩衝區的字節,圓形表示接收緩衝區的字節,每個顏色的框和箭頭表示每次滑動的區域.
假設發送方窗口大小爲3,接收方窗口大小爲2,這個窗口大小是計算得到的,並不是固定大小,具體計算方式說實話我還沒來得及研究,以後研究了可以補充上,如果對這個感興趣可以去查查.
具體的滑動步驟如下:

  1. 發送方向接收方發送了1,2,3三個字節,接收方收到1,2字節之後,發送接收1的ack確認包給發送方,然後發送方接收到ack包之後向後滑動一位.
  2. 以此類推,當然接收方處理字節的順序並不是固定的,就是誰處理的快就先回復誰的ack,等到綠色窗口時,接收方先確認5,在此期間,當發送方接收到5的ack之後,並不會滑動窗口,因爲發送方窗口是連續的,等到接收到4的ack包之後纔會向後滑動,也就是等接收4的ack之後,滑動窗口直接滑動到5的下一位,也就是6的位置.期間如果4一直未收到ack確認包,那等到重發計時器時間到了就會進行數據重發,最終收到4的ack之後進行滑動.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章