TCP協議分析




TCP協議

1、TCP 通過以下方式提供可靠性:

    ◆ 應用程序分割爲TCP認爲最合適發送的數據塊。由TCP傳遞給IP的信息單位叫做報文段。

    ◆ 當TCP發出一個報文段後,它啓動一個定時器,等待目的端確認收到這個報文段。如果不能記時收到一個確認,它 就重發這個報文段。

    ◆ 當TCP收到發自TCP連接另一端的數據,它將發送一個確認。這個確認不是立即發送,通常延遲幾分之一秒。

    ◆ TCP將保持它首部和數據的檢驗和。這是一個端到端的檢驗和,目的是檢測數據在傳輸過程中的任何變化如果收到報文段的檢驗和有差錯,TCP將丟棄這個報文段和不確認收到這個報文段。

    ◆ 既然TCP報文段作爲IP數據報來傳輸,而IP數據報的到達可能失序,因此TCP報文段的到達也可能失序。如果必要,TCP將對收到的數據進行排序,將收到的數據以正確的順序交給應用層。

    ◆ 既然IP數據報會發生重複,TCP連接端必須丟棄重複的數據。

    ◆ TCP還能提供流量控制,TCP連接的每一方都有固定大小的緩衝空間。TCP的接收端只允許另一端發送接收端緩衝區所能接納的數據。這將防止較快主機致使較慢主機的緩衝區溢出。

  另外,TCP對字節流的內容不作任何解釋。

wKiom1haJ3iDNyBpAAD_-tbQuVY781.png




說明:
(1)每個TCP段都包括源端和目的端的端口號,用於尋找發送端和接收端的應用進程。這兩個值加上IP首部的源端IP地址和目的端IP地址唯一確定一個TCP連接。
(2)序號用來標識從TCP發送端向接收端發送的數據字節流,它表示在這個報文段中的第一個數據字節。如果將字節流看作在兩個應用程序間的單向流動,則TCP用序號對每個字節進行計數。
(3)當建立一個新連接時,SYN標誌變1。序號字段包含由這個主機選擇的該連接的初始序號ISN,該主機要發送數據的第一個字節的序號爲這個ISN加1,因爲SYN標誌使用了一個序號。
(4)既然每個被傳輸的字節都被計數,確認序號包含發送確認的一端所期望收到的下一個序號。因此,確認序號應當時上次已成功收到數據字節序號加1。只有ACK標誌爲1時確認序號字段纔有效。
(5)發送ACK無需任何代價,因爲32位的確認序號字段和ACK標誌一樣,總是TCP首部的一部分。因此一旦一個連接建立起來,這個字段總是被設置,ACK標誌也總是被設置爲1。
(6)TCP爲應用層提供全雙工的服務。因此,連接的每一端必須保持每個方向上的傳輸數據序號。
(7)TCP可以表述爲一個沒有選擇確認或否認的華東窗口協議。因此TCP首部中的確認序號表示發送方已成功收到字節,但還不包含確認序號所指的字節。當前還無法對數據流中選定的部分進行確認。
(8)首部長度需要設置,因爲任選字段的長度是可變的。TCP首部最多60個字節。
(9)6個標誌位中的多個可同時設置爲1
    ◆ URG-緊急指針有效
    ◆ ACK-確認序號有效
    ◆ PSH-接收方應儘快將這個報文段交給應用層
    ◆ RST-重建連接
    ◆ SYN-同步序號用來發起一個連接
    ◆ FIN-發送端完成發送任務
(10)TCP的流量控制由連接的每一端通過聲明的窗口大小來提供。窗口大小爲字節數,起始於確認序號字段指明的值,這個值是接收端期望接收的字節數。窗口大小是一個16爲的字段,因而窗口大小最大爲65535字節。
(11)檢驗和覆蓋整個TCP報文端:TCP首部和TCP數據。這是一個強制性的字段,一定是由發送端計算和存儲,並由接收端進行驗證。TCP檢驗和的計算和UDP首部檢驗和的計算一樣,也使用僞首部。
(12)緊急指針是一個正的偏移量,黃蓉序號字段中的值相加表示緊急數據最後一個字節的序號。TCP的緊急方式是發送端向另一端發送緊急數據的一種方式。
(13)最常見的可選字段是最長報文大小MMS,每個連接方通常都在通信的第一個報文段中指明這個選項。它指明本端所能接收的最大長度的報文段。

二、TCP連接的建立和終止

1、建立連接協議
 (1) 請求端發送一個SYN段指明客戶打算連接的服務器的端口,隱疾初始序號(ISN),這個SYN報文段爲報文段1。
 (2) 服務器端發回包含服務器的初始序號的SYN報文段(報文段2)作爲應答。同時將確認序號設置爲客戶的ISN加1以對客戶的SYN報文段進行確認。一個SYN將佔用一個序號。
 (3) 客戶必須將確認序號設置爲服務器的ISN加1以對服務器的SYN報文段進行確認(報文段3)。
   這3個報文段完成連接的建立,稱爲三次握手。發送第一個SYN的一端將執行主動打開,接收這個SYN併發回下一個SYN的另一端執行被動打開。

2、連接終止協議
   由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的連接。收到一個FIN只意味着這一方向上沒有數據流動,一個TCP連接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
  (1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送(報文段4)。
  (2) 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
  (3) 服務器關閉客戶端的連接,發送一個FIN給客戶端(報文段6)。
  (4) 客戶段發回確認,並將確認序號設置爲收到序號加1(報文段7)。

3、連接建立的超時
   如果與服務器無法建立連接,客戶端就會三次向服務器發送連接請求。在規定的時間內服務器未應答,則連接失敗。

4、最大報文段長度MSS
   最大報文段長度表示TCP傳往另一端的最大塊數據的長度。當一個連接建立時,連接的雙方都要通告各自的MSS。
一般,如果沒有分段發生,MSS還是越大越好。報文段越大允許每個報文段傳送的數據越多,相對IP和TCP首部有更高的網絡利用率。當TCP發送一個SYN時,它能將MSS值設置爲外出接口的MTU長度減去IP首部和TCP首部長度。對於以太網,MSS值可達1460。
   如果目的地址爲非本地的,MSS值通常默認爲536,是否本地主要通過網絡號區分。MSS讓主機限制另一端發送數據報的長度,加上主機也能控制它發送數據報的長度,這將使以較小MTU連接到一個網絡上的主機避免分段。

5、 TCP的半關閉
   TCP提供了連接的一端在結束它的發送後還能接收來自另一端數據的能力,這就是TCP的半關閉。
客戶端發送FIN,另一端發送對這個FIN的ACK報文段。當收到半關閉的一端在完成它的數據傳送後,才發送FIN關閉這個方向的連接,客戶端再對這個FIN確認,這個連接才徹底關閉。

6、2MSL連接
   TIME_WAIT狀態也稱爲2MSL等待狀態。每個TCP必須選擇一個報文段最大生存時間(MSL)。它是任何報文段被丟棄前在網絡的最長時間。
   處理原則:當TCP執行一個主動關閉,併發回最後一個ACK,該連接必須在TIME_WAIT狀態停留的時間爲2MSL。這樣可以讓TCP再次發送最後的ACK以避免這個ACK丟失(另一端超時並重發最後的FIN)。這種2MSL等待的另一個結果是這個TCP連接在2MSL等待期間,定義這個連接的插口不能被使用。

7、平靜時間
   TCP在重啓的MSL秒內不能建立任何連接,這就是平靜時間。
8、FIN_WAIT_2狀態
   在FIN_WAIT_2狀態我們已經發出了FIN,並且另一端也對它進行了確認。只有另一端的進程完成了這個關閉,我們這端纔會從FIN_WAIT_2狀態進入TIME_WAIT狀態。這意味着我們這端可能永遠保持這個狀態,另一端也將處於CLOSE_WAIT狀態,並一直保持這個狀態直到應用層決定進行關閉。
9、復位報文段
   TCP首部的RST位是用於復位的。一般,無論合適一個報文端發往相關的連接出現錯誤,TCP都會發出一個復位報文段。主要情況:
(1)到不存在的端口的連接請求;
(2)異常終止一個連接。

10、同時打開
   爲了處理同時打開,對於同時打開它僅建立一條連接而不是兩條連接。兩端幾乎在同時發送SYN,並進入SYN_SENT狀態。當每一端收到SYN時,狀態變爲SYN_RCVD,同時他們都再發SYN並對收到的SYN進行確認。當雙方都收到SYN及相應的ACK時,狀態都變爲ESTABLISHED。一個同時打開的連接需要交換4個報文段,比正常的三次握手多了一次。

11、 同時關閉
   當應用層發出關閉命令,兩端均從ESTABLISHED變爲FIN_WAIT_1。這將導致雙方各發送一個FIN,兩個FIN經過網絡傳送後分別到達另一端。收到FIN後,狀態由FIN_WAIT_1變爲CLOSING,併發送最後的ACK。當收到最後的ACK,狀態變爲TIME_WAIT。同時關閉和正常關閉的段減緩數目相同。

12、TCP選項
   每個選項的開始是1字節的kind字段,說明選項的類型。

   Kind=1:選項表結束(1字節)     Kind=1:無操作(1字節)     Kind=2:最大報文段長度(4字節)     Kind=3:窗口擴大因子(4字節)     Kind=8:時間戳(10字節)

三、TCP的超時和重傳

   對於每個TCP連接,TCP管理4個不同的定時器。
   (1) 重傳定時器用於當希望收到另一端的確認。
   (2) 堅持定時器使窗口大小信息保持不斷流動,即使另一端關閉了其接收窗口。
   (3) 保活定時器可檢測到一個空閒連接的另一端何時崩潰或重啓。
   (4) 2MSL定時器測量一個連接處於TIME_WAIT狀態的時間。

1、往返時間測量
   TCP超時和重傳重最重要的就是對一個給定連接的往返時間(RTT)的測量。由於路由器和網絡流量均會變化,因此TCP應該跟蹤這些變化並相應地改變超時時間。首先TCP必須測量在發送一個帶有特別序號地字節和接收到包含該字節地確認之間的RTT。

2、擁塞避免算法
   該算法假定由於分組收到損壞引起的丟失是非常少的,因此分組丟失就意味着在源主機和目的主機之間的某處網絡上發生了阻塞。有兩種分組丟失的指示:發生超時和收到重複的確認。擁塞避免算法需要對每個連接維持兩個變量:一個擁塞窗口cwnd和一個慢啓動門限ssthresh。
   (1) 對一個給定的連接,初始化cwnd爲1個報文段,ssthresh爲65535個字節。
   (2) TCP輸出例程的輸出不能超過cwnd和接收方通告窗口的大小。擁塞避免是發送方使用的流量控制。前者是發送方感受到的網絡擁塞的估計,而後者則與接收方在該連接上的可用緩存大小有關。
   (3) 當擁塞發生時,ssthresh被設置爲當前窗口大小的一般(cwnd和接收方通告窗口大小的最小值,但最小爲2個報文段)。此外,如果是超時引起了擁塞,則cwnd被設置爲1個報文段。
   (4) 當新的數據被對方確認時,就增加cwnd,但增加的方法依賴與是否正在進行慢啓動或擁塞避免。如果cwnd小於或等於ssthresh,則正在進行慢啓動,否則正在進行擁塞避免。

3、快速重傳和快速恢復算法
   如果我們一連串收到3個或以上的重複ACK,就非常可能是一個報文段丟失了。於是我們就重傳丟失的數據報文段,而無需等待超時定時器溢出。
  (1) 當收到第3個重複的ACK時,將ssthresh設置爲當前擁塞窗口cwnd的一半,重傳丟失的報文段,設置cwnd爲ssthresh加上3倍的報文段大小。
  (2) 每次收到另一個重複的ACK時,cwnd增加1個報文段大小併發送一個1個分組,如果允許的話。
  (3) 當下一個確認新數據的ACK到達時,設置cwnd爲ssthresh,這個ACK應該時在進行重傳後的一個往返時間內對步驟1重重傳的確認。另外,這個ACK也應該是對丟失的分組和收到的第一個重複的ACK之間的所有中間報文段的確認。

4、 ICMP差錯
   TCP如何處理一個給定的連接返回的ICMP差錯。TCP能夠遇到的最常見的ICMP差錯就是源站抑制、主機不可達和網絡不可達。
  (1) 一個接收到的源站抑制引起擁塞窗口cwnd被置爲1個報文段大小來發起慢啓動,但是慢啓動門限ssthresh沒有變化,所以窗口將打開直到它開放了所有的通路或者發生了擁塞。
  (2) 一個接收到的主機不可達或網絡不可達實際都被忽略,因爲這兩個差錯都被認爲是短暫現象。TCP試圖發送引起該差錯的數據,儘管最終有可能會超時。

5、重新分組:
   當TCP超時並重傳時,它並不一定要重傳同樣的報文段,相反,TCP允許進行重新分組而發送一個較大的報文段。這是允許的,因爲TCP是使用字節序號而不是報文段序號來進行識別它所要發送的數據和進行確認。

四、TCP的堅持定時器

   ACK的傳輸並不可靠,也就是說,TCP不對ACK報文段進行確認,TCP只確認那些包含數據的ACK報文段。爲了防止因爲ACK報文段丟失而雙方進行等待的問題,發送方用一個堅持定時器來週期性地向接收方查詢。這些從發送方發出地報文段稱爲窗口探查。

五、TCP的保活定時器
   如果一個給定的連接在2小時內沒有任何動作,那麼服務器就向客戶發送一個探查報文段。客戶主機必須處於以下4個狀態之一。
   (1) 客戶主機依然正常運行,並從服務器可達。客戶的TCP響應正常,而服務器也知道對方的正常工作的。服務器在2小時內將保活定時器復位。
   (2) 客戶主機已經崩潰,並且關閉或者正在重新啓動。在任何一種情況下,客戶的TCP都沒有響應。服務器將不能收到對探查的響應,並在75秒後超時。總共發送10個探查,間隔75秒。
   (3) 客戶主機崩潰並已經重新啓動。這是服務器將收到一個對其保活探查的響應,但這個響應是一個復位,使得服務器終止這個連接。
   (4) 客戶主機正常運行,但是從服務器不可達。

六、TCP的一些性能

1、 路徑MTU發現:
   TCP的路徑MTU發現按如下方式進行:在連接建立時,TCP使用輸出接口或對段聲明的MSS中的最下MTU作爲其實的報文段大小。路徑MTU發現不允許TCP超過對端聲明的MSS。如果對端沒有指定一個MSS,則默認爲536。
   一旦選定了起始的報文段大小,在該連接上的所有被TCP發送的IP數據報都將被設置DF位。如果中間路由器需要對一個設置了DF標誌的數據報進行分片,它就丟棄這個數據報,併產生一個ICMP的“不能分片”差錯。
   如果收到這個ICMP差錯,TCP就減少段大小並進行重傳。如果路由器產生的是一個較新的該類ICMP差錯,則報文段大小被設置位下一跳的MTU減去IP和TCP的首部長度。如果是一個較舊的該類ICMP差錯,則必須嘗試下一個可能的最小MTU。

2、 長肥管道
   一個連接的容量=帶寬X時延(RTT)。具有大的帶寬時延乘積的網絡稱爲長肥網絡(LFN)。一個運行在LFN的TCP連接稱爲長肥管道。管道可以被水平拉長(一個長的RTT),或被垂直拉高(較高的帶寬),或兩個方向拉伸。

3、窗口擴大選項:
   窗口擴大選項使TCP的窗口定義從16位增加到32位,這並不是通過修改TCP首部來實現的,TCP首部仍然使用16位,而是通過定義一個選項實現對16位的擴大操作來完成的。

4、時間戳選項:
   時間戳選項使發送方在每個報文段中放置一個時間戳值。接收方在確認中返回這個數值,從而允許發送方爲每一個收到的ACK計算RTT。
 
七、TCP的三次握手與四次揮手
1、建立連接協議(三次握手)
(1)客戶端發送一個帶SYN標誌的TCP報文到服務器。這是三次握手過程中的報文1。
(2) 服務器端迴應客戶端的,這是三次握手中的第2個報文,這個報文同時帶ACK標誌和SYN標誌。因此它表示對剛纔客戶端SYN報文的迴應;同時又標誌SYN給客戶端,詢問客戶端是否準備好進行數據通訊。
(3) 客戶必須再次迴應服務段一個ACK報文,這是報文段3。
2、連接終止協議(四次揮手)
   由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的連接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP連接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
 (1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送(報文段4)。
 (2) 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
 (3) 服務器關閉客戶端的連接,發送一個FIN給客戶端(報文段6)。
 (4) 客戶段發回ACK報文確認,並將確認序號設置爲收到序號加1(報文段7)。
CLOSED: 這個沒什麼好說的了,表示初始狀態。
LISTEN: 這個也是非常容易理解的一個狀態,表示服務器端的某個SOCKET處於監聽狀態,可以接受連接了。
SYN_RCVD: 這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一箇中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最後一個ACK報文不予發送。因此這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。
SYN_SENT: 這個狀態與SYN_RCVD遙想呼應,當客戶端SOCKET執行CONNECT連接時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。
ESTABLISHED:這個容易理解了,表示連接已經建立了。
FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連接,向對方發送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。
FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點數據需要傳送給你,稍後再關閉連接。
TIME_WAIT: 表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。
CLOSING: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。
CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後發送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有數據發送給對方,如果沒有的話,那麼你也就可以close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。
LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。
最後有2個問題的回答,我自己分析後的結論(不一定保證100%正確)
1、 爲什麼建立連接協議是三次握手,而關閉連接卻是四次握手呢?
這是因爲服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裏來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你所有的數據都全部發送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要發送一些數據給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這裏的ACK報文和FIN報文多數情況下都是分開發送的。
2、 爲什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?
這是因爲:雖然雙方都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣);但是因爲我們必須要假想網絡是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於LAST_ACK狀態下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章