1. 程式人生 > >TCP/IP之TCP協議首部、三次握手、四次揮手、FSM

TCP/IP之TCP協議首部、三次握手、四次揮手、FSM

timestamp 我希望 可能 傳輸 同步 調用 emc ron 超時

TCP包頭

<--------------------------------32 位------------------------------>

0                8                16               24               32
|----------------|----------------|----------------|----------------|  -----
|            Source port          |         Destination port        |    |
|-------------------------------------------------------------------|    |
|                               序 號                                |
|-------------------------------------------------------------------|   20字節
|                              確 認 號                              |   固 定
|-------------------------------------------------------------------|   首 部
|        |           | U A P R S F|                                 |    
|數據偏移 |  保 留    | R C S S Y I|               窗口               |
|        |           | G K H T N N|                                 |    |
|-------------------------------------------------------------------|    |
|              校 驗 和            |             緊急指針             |    
|-------------------------------------------------------------------|   -----
|              選 項 (長 度 可 變)                 |      填充      |
---------------------------------------------------------------------

TCP包頭

  • 源端口、目標端口 :計算機上的進程要和其他進程通信是要通過計算機端口的,而一個計算機端口某個時刻只能被一個進程占用,所以通過指定源端口和目標端口,就可以知道是哪兩個進程需要通信。源端口、目標端口是用16位表示的,可推算計算機的端口個數為2^16個。

  • 序列號 :表示本報文段所發送數據的第一個字節的編號。在TCP連接中所傳送的字節流的每一個字節都會按順序編號。由於序列號由32位表示,所以每2^32個字節,就會出現序列號回繞,再次從 0 開始。

  • 確認號 :表示接收方期望收到發送方下一個報文段的第一個字節數據的編號。也就是告訴發送方:我希望你(指發送方)下次發送的數據的第一個字節數據的編號為此確認號。

  • 數據偏移 :表示TCP報文段的首部長度,共4位,由於TCP首部包含一個長度可變的選項部分,需要指定這個TCP報文段到底有多長。它指出 TCP 報文段的數 據起始處距離 TCP 報文段的起始處有多遠。該字段的單位是32位(即4個字節為計算單位),4位二進制最大表示15,所以數據偏移也就是TCP首部最大60字節。

  • URG :表示本報文段中發送的數據是否包含緊急數據。後面的緊急指針字段(urgent pointer)只有當URG=1時才有效。

  • ACK :表示是否前面確認號字段是否有效。只有當ACK=1時,前面的確認號字段才有效。TCP規定,連接建立後,ACK必須為1,帶ACK標誌的TCP報文段稱為確認報文段。

  • PSH :提示接收端應用程序應該立即從TCP接收緩沖區中讀走數據,為接收後續數據騰出空間。如果為1,則表示對方應當立即把數據提交給上層應用,而不是緩存起來,如果應用程序不將接收到的數據讀走,就會一直停留在TCP接收緩沖區中。

  • RST :如果收到一個RST=1的報文,說明與主機的連接出現了嚴重錯誤(如主機崩潰),必須釋放連接,然後再重新建立連接。或者說明上次發送給主機的數據有問題,主機拒絕響應,帶RST標誌的TCP報文段稱為復位報文段。

  • SYN :在建立連接時使用,用來同步序號。當SYN=1,ACK=0時,表示這是一個請求建立連接的報文段;當SYN=1,ACK=1時,表示對方同意建立連接。SYN=1,說明這是一個請求建立連接或同意建立連接的報文。只有在前兩次握手中SYN才置為1,帶SYN標誌的TCP報文段稱為同步報文段。

  • FIN :表示通知對方本端要關閉連接了,標記數據是否發送完畢。如果FIN=1,即告訴對方:“我的數據已經發送完畢,你可以釋放連接了”,帶FIN標誌的TCP報文段稱為結束報文段。

  • 窗口大小 :表示現在允許對方發送的數據量,也就是告訴對方,從本報文段的確認號開始允許對方發送的數據量,達到此值,需要ACK確認後才能再繼續傳送後面數據,由Window size value * Window size scaling factor(此值在三次握手階段TCP選項Window scale協商得到)得出此值。

  • 校驗和 :提供額外的可靠性。

  • 緊急指針 :標記緊急數據在數據字段中的位置。

  • 選項部分 :其最大長度可根據TCP首部長度進行推算。TCP首部長度用4位表示,選項部分最長為:(2^4-1)*4-20=40字節。

    常見選項:

    • 最大報文段長度:Maxium Segment Size,MSS,通常1460字節

    • 窗口擴大:Window Scale

    • 時間戳: Timestamps

    • 1 最大報文段長度MSS(Maximum Segment Size) 指明自己期望對方發送TCP報文段時那個數據字段的長度。比如:1460字節。數據字段的長度加上TCP首部的長度才等於整個TCP報文段的長度。 MSS不宜設的太大也不宜設的太小。若選擇太小,極端情況下,TCP報文段只含有1字節數據,在IP層傳輸的數據報的開銷至少有40字節(包括TCP報文段的首部和IP數據報的首部)。這樣,網絡的利用率就不會超過1/41。若TCP報文段非常長,那麽在IP層傳輸時就有可能要分解成多個短數據報片。在終點要把收到的各個短數據報片裝配成原來的TCP報文段。當傳輸出錯時還要進行重傳,這些也都會使開銷增大。因此MSS應盡可能大,只要在IP層傳輸時不需要再分片就行。在連接建立過程中,雙方都把自己能夠支持的MSS寫入這一字段。MSS只出現在SYN報文中。即:MSS出現在SYN=1的報文段中。

      • MTU和MSS值的關系:MTU=MSS+IP Header+TCP Header
      • 通信雙方最終的MSS值=較小MTU-IP Header-TCP Header
    • 2 窗口擴大
      為了擴大窗口,由於TCP首部的窗口大小字段長度是16位,所以其表示的最大數是65535。但是隨著時延和帶寬比較大的通信產生(如衛星通信),需要更大的窗口來滿足性能和吞吐率,所以產生了這個窗口擴大選項。

    • 3 時間戳
      可以用來計算RTT(往返時間),發送方發送TCP報文時,把當前的時間值放入時間戳字段,接收方收到後發送確認報文時,把這個時間戳字段的值復制到確認報文中,當發送方收到確認報文後即可計算出RTT。也可以用來防止回繞序號PAWS,也可以說可以用來區分相同序列號的不同報文。因為序列號用32為表示,每2^32個序列號就會產生回繞,那麽使用時間戳字段就很容易區分相同序列號的不同報文。

映射第四層到應用程序

TCP協議PORT

  • 傳輸層通過port號,確定應用層協議
  • Port number:
    • tcp:傳輸控制協議,面向連接的協議;通信前需要建立虛擬鏈路;結束後拆除鏈路。
      0-65535
    • udp:User Datagram Protocol,無連接的協議。
      0-65535
  • IANA:互聯網數字分配機構(負責域名,數字資源,協議分配)
    • 0-1023:系統端口或特權端口(僅管理員可用) ,眾所周知,永久的分配給固定的系統應用使用,22/tcp(ssh), 80/tcp(http), 443/tcp(https)

    • 1024-49151:用戶端口或註冊端口,但要求並不嚴格,分配給程序註冊為某應用使用,1433/tcp(SqlServer), 1521/tcp(oracle),3306/tcp(mysql),11211/tcp/udp(memcached)

    • 49152-65535:動態端口或私有端口,客戶端程序隨機使用的端口。
      其範圍的定義:

      /proc/sys/net/ipv4/ip_local_port_range
      

TCP三次握手

握手 客戶端狀態 客戶端TCP 方向 服務器TCP 服務器狀態 描述
第一次 初始:CLOSED
發送:SYN-SENT
SYN=1, seq=x ----> 初始:LISTEN
接收:SYN-RECEIVED
同步(SYN)
第二次 接收:SYN-SENT <---- SYN=1, ACK=1, seq=y, ack=x+1 發送:SYN-RECEIVED 同步、確認(ACK)
第三次 發送:ESTABLISHED ACK=1, seq=x+1, ack=y+1 ----> 接收:ESTABLISHED 確認(ACK)
數據傳輸 <--->

TCP四次揮手

揮手 客戶端狀態 客戶端TCP 方向 服務器TCP 服務器狀態 描述
第一次 初始:ESTABLISHED
發送:FIN-WAIT-1
FIN=1, seq=u ----> 初始:ESTABLISHED
接收:CLOSE-WAIT
分手(FIN)
第二次 接收:FIN-WAIT-2 <---- ACK=1, seq=v, ack=u+1 發送:CLOSE-WAIT 好的(ACK)
第三次 接收:FIN-WAIT-2 <---- FIN=1, ACK=1, seq=w, ack=u+1 發送:LAST-ACK 分手(FIN+ACK)
第四次 發送:TIME-WAIT
2MSL後:CLOSED
ACK=1, seq=u+1, ack=w+1 ----> 接收:CLOSED 好的(ACK)

有限狀態機FSM :Finite State Machine

FSM 說明
CLOSED 沒有任何連接狀態
LISTEN 偵聽狀態,等待來自遠方TCP端口的連接請求
SYN-SENT 在發送連接請求後,等待對方確認
SYN-RECEIVED 在收到和發送一個連接請求後,等待對方確認
ESTABLISHED 代表傳輸連接建立,雙方進入數據傳送狀態
FIN-WAIT-1 主動關閉,主機已發送關閉連接請求,等待對方確認
FIN-WAIT-2 主動關閉,主機已收到對方關閉傳輸連接確認,等待對方發送關閉傳輸連接請求
TIME-WAIT 完成雙向傳輸連接關閉,等待所有分組消失
CLOSE-WAIT 被動關閉,收到對方發來的關閉連接請求,並已確認
LAST-ACK 被動關閉,等待最後一個關閉傳輸連接確認,並等待所有分組消失
CLOSING 雙方同時嘗試關閉傳輸連接,等待對方確認

客戶端先發送一個FIN給服務端,自己進入了FIN_WAIT_1狀態,這時等待接收服務端的報文,該報文會有三種可能:

  • 只有服務端的ACK
  • 只有服務端的FIN
  • 基於服務端的ACK,又有FIN

1、只收到服務器的ACK,客戶端會進入FIN_WAIT_2狀態,後續當收到服務端的FIN時,回應發送一個ACK,會進入到TIME_WAIT狀態,這個狀態會持續2MSL(TCP報文段在網絡中的最大生存時間,RFC 1122標準的建議值是2min)。客戶端等待2MSL,是為了當最後一個ACK丟失時,可以再發送一次。因為服務端在等待超時後會再發送一個FIN給客戶端,進而客戶端知道ACK已丟失。

2、只有服務端的FIN時,回應一個ACK給服務端,進入CLOSING狀態,然後接收到服務端的ACK時,進入TIME_WAIT狀態。

3、同時收到服務端的ACK和FIN,直接進入TIME_WAIT狀態。

客戶端的典型狀態轉移

  • 客戶端通過connect系統調用主動與服務器建立連接connect系統調用首先給服務器發送一個同步報文段,使連接轉移到SYN_SENT狀態。
  • 此後connect系統調用可能因為如下兩個原因失敗返回:

1、如果connect連接的目標端口不存在(未被任何進程監聽),或者該端口仍被處於TIME_WAIT狀態的連接所占用(見後文),則服務器將給客戶端發送一個復位報文段,connect調用失敗。

2、如果目標端口存在,但connect在超時時間內未收到服務器的確認報文段,則connect調用失敗。

connect調用失敗將使連接立即返回到初始的CLOSED狀態。如果客戶端成功收到服務器的同步報文段和確認,則connect調用成功返回,連接轉移至ESTABLISHED狀態。

當客戶端執行主動關閉時,它將向服務器發送一個結束報文段,同時連接進入FIN_WAIT_1狀態。若此時客戶端收到服務器專門用於確認目的的確認報文段,則連接轉移至FIN_WAIT_2狀態。當客戶端處於FIN_WAIT_2狀態時,服務器處於CLOSE_WAIT狀態,這一對狀態是可能發生半關閉的狀態。此時如果服務器也關閉連接(發送結束報文段),則客戶端將給予確認並進入TIME_WAIT狀態。

客戶端從FIN_WAIT_1狀態可能直接進入TIME_WAIT狀態(不經過FIN_WAIT_2狀態),前提是處於FIN_WAIT_1狀態的服務器直接收到帶確認信息的結束報文段(而不是先收到確認報文段,再收到結束報文段)。

處於FIN_WAIT_2狀態的客戶端需要等待服務器發送結束報文段,才能轉移至TIME_WAIT狀態,否則它將一直停留在這個狀態。如果不是為了在半關閉狀態下繼續接收數據,連接長時間地停留在IN_WAIT_2狀態並無益處。連接停留在FIN_WAIT_2狀態的情況可能發生在:客戶端執行半關閉後,未等服務器關閉連接就強行退出了。此時客戶端連接由內核來接管,可稱之為孤兒連接(和孤兒進程類似)。

Linux為了防止孤兒連接長時間存留在內核中,定義了兩個內核參數:

  • /proc/sys/net/ipv4/tcp_max_orphans 指定內核能接管的孤兒連接數目
  • /proc/sys/net/ipv4/tcp_fin_timeout 指定孤兒連接在內核中生存的時間

有限狀態機

TCP協議中的三次握手和四次揮手

客戶機端的三次握手和四次揮手、服務器端的三次握手和四次揮手

graph TB C(CLOSED) S(SYN_SENT) E(ESTABLISHED) F1(FIN_WAIT_1) F2(FIN_WAIT_2) T(TIME_WAIT) SC(CLOSED) L(LISTEN) SR(SYN_RCVD) SE(ESTABLISHED) CW(CLOSE_WAIT) LA(LAST_ACK) subgraph 客戶機端的三次握手和四次揮手 C --"發送SYN"--> S S --"接收SYN和ACK,發送ACK"--> E E --"發送FIN"--> F1 F1 --"接收確認,不發送任何信息"--> F2 F2 --"接收FIN,發送ACK"--> T T --"等待30秒"--> C end subgraph 服務器端的三次握手和四次揮手 SC --監聽--> L L --"接收SYN,發送SYN和ACK"--> SR SR --"接收ACK,不發送任何信息"--> SE SE --"接收FIN,發送ACK"--> CW CW --"發送FIN"--> LA LA --"接收ACK,不發送任何信息"--> SC end

TCP/IP之TCP協議首部、三次握手、四次揮手、FSM