一條HTTP請求的生命週期(二)-- TCP, 本文基於 RFC793

wzyAcyy 發表於 2022-01-27

《網路是怎麼連線的》的第二章介紹了作業系統中的協議棧和網路卡是如何將應用程式的訊息發給伺服器的:

  1. 解建立套接字
  2. 連線伺服器
  3. 收發資料
  4. 從伺服器斷開連線並刪除套接字
  5. IP與乙太網的包收發操作
  6. 用UDP收發資料的操作

其中涉及到很多的概念:TCP IP 乙太網 UDP

本文基於rfc793 及其後續修訂版,摘錄其中部分內容,試著找一找工作中的使用場景。

TCP

黑體字見附錄

0.附錄(基本在百度百科上搜的)

  1. 主機到主機 host-to-host:對應OSI七層模型的傳輸層。
  2. 分組交換 packet switching:通訊雙方以分組為單位、使用儲存-轉發機制實現資料互動的通訊方式。也稱包交換,將使用者通訊的資料劃分成多個更小的等長資料段。
    例如:TCP的儲存-轉發,TCP有一個收發緩衝區,將資料組裝成網路包傳送。
  3. 魯棒性 robust:健壯和強壯的意思,在異常和危險情況下系統不奔潰、不當機的能力。
  4. 擁塞 congestion:擁塞是指到達通訊子網中分組數量過多來不及處理,以致引起這部分乃至整個網路效能下降的現象,嚴重時甚至會導致網路通訊業務陷入停頓。類比交通阻塞。
  5. 面向連線:connection-oriented,具備以下特徵:建立一條虛電路(比如3次握手),排序(序號),確認(ACK),流量控制。
  6. 端到端:end-to-end,端到端是網路連線。網路要通訊,無論中間有多少機器,只要在兩頭(源和目的)建立連線即端對端連線。
  7. 分層結構:上層呼叫下層,下層對上層一無所知。例如網路七層模型
  8. 多網路:也稱多重網路,使用多種通訊媒體的網路群組。
  9. 通訊媒體:也稱傳輸媒介,可分為有線(光纖,雙絞線,同軸電纜)和無線
  10. 硬線連線:??查不到資料
  11. 電路交換:主要應用於電話通訊。
  12. 基於時鐘:clock-based,時鐘即cpu時鐘,是CPU自帶的時鐘。CPU時鐘週期,通常為節拍脈衝或T週期,它是處理操作的最基本的單位。右擊我的電腦 --> 屬性,可以看到電腦的GHz。
  13. 乙太網:ETHERNET,是目前最常用的計算機區域網技術。
  14. 包交換器:應用了通訊技術,對分組的資料資訊進行程式處理的通訊裝置。
  15. 驅動程式:是一種可以使計算機和裝置進行相互通訊的特殊程式。相當於硬體的介面,作業系統只有通過這個介面,才能控制硬體裝置的工作。

1.簡介

高可靠、主機到主機協議,用於分組交換計算機通訊網路。
本文介紹程式實現TCP,使用者和程式呼叫TCP服務介面時,TCP協議提供哪些功能。

1.1 目的

為解決軍事通訊網路的可靠性和可用性而生,同時適用於政府和民間網路通訊。
關注計算機通訊系統不可靠時的魯棒性擁塞時的可用性。

TCP面向連線端到端的高可靠協議。適用於分層結構協議且支援多網路應用程式。TCP假設下層協議是不可靠的。原則上適用範圍從硬線連線到分組交換或電路交換網路

                       Protocol Layering

                    +---------------------+
                    |     higher-level    |
                    +---------------------+
                    |        TCP          |
                    +---------------------+
                    |  internet protocol  |
                    +---------------------+
                    |communication network|
                    +---------------------+

1.2 範圍

用於多網路環境下程式間可靠通訊服務。

1.3 關於文件

描述了 TCP服務之間,以及TCP與高層次協議互動的規範。
剩餘章節簡潔了協議的介面和操作
章節二:總結了TCP設計的基本原理
章節三:提供了TCP在各種事件發生時(新段的到達、使用者呼叫、錯誤等)所需要的動作的詳細描述,以及TCP段格式的詳細資訊。

1.4 介面

TCP介面一端是使用者或者應用程式,另一端是底層協議如IP協議。

應用程式和TCP間的介面將詳細闡述。介面包含一套呼叫集合。例如開啟關閉連線,建立在連線上的收發資料。應用程式和TCP之間是非同步通訊。

TCP協議設計出來工作於通用的網際網路環境上,本文假設底層協議是IP

1.5 操作

如上所述,TCP的主要目的是程式對之間提供可靠、安全的邏輯電路和連線服務。

為了在不太可靠的網際網路通訊系統上提供如上服務,需要以下設施。

  • 基本的資料傳輸
  • 可靠能力
  • 流量控制
  • 多路複用
  • 連線
  • 優先順序和安全

1.5.1 基本的傳輸能力

TCP按一定的位元組長度打包成,能夠雙向傳輸連續的八位(octets)位元組流。
通常由TCPs決定何時阻塞或推送資料。
TCP定義了一個push功能,可以立即推送資料。

1.5.2 可靠性

目的:當資料被網路通訊系統損壞、丟失、複製或無序的傳輸時,TCP必須進行資料恢復。
方案
丟失:傳送方為每個位元組分配序列號,接收方返回確認(ACK)。超時時間內接收方沒有收到ACK,資料將被重傳。
有序和去重:在接收端,使用序列號正確地排列,並去重。
損壞:給每個傳輸的段新增一個校驗和,在接收端做校驗並丟棄損壞的段。

TCP可以從網路通訊系統的錯誤中恢復。

1.5.3 流量控制

如果傳送速率過快來不及接收可能會丟包,重發,網路擁塞。
TCP通過“視窗”機制給接收方提供一種控制傳送方流量速率的方法。

  1. 接收方收到資料並將資料交給應用程式之後,返回視窗給傳送方。
  2. 傳送方通過視窗大小來調整傳送速率。

視窗即當前接收緩衝區的大小。

1.5.4 多路複用

  1. 允許單個主機的多個程式使用TCP設施
  2. 一個套接字給多個連線使用

TCP埠和來自網路層的ip地址組成套接字,一對套接字標識一個連線。一個套接字複用於多個連線。

不難發現,多路複用的關鍵是套接字
套接字:IP地址+埠號

1.5.5 連線

可靠性和流控制機制要求TCPs為每個資料流初始化和維護某些狀態資訊。
這些狀態資訊包括套接字、序列號和視窗大小,被稱為一個連線。
連線由兩端的一對套接字唯一標識。

當兩個程式想要通訊時,它們的TCPs必須首先建立一個連線(初始化兩邊的狀態資訊),通訊完成時,連線被終止或關閉。

由於連線建立在不可靠的主機之間和不可靠的internet通訊系統上,為了避免連線的錯誤初始化,使用了一套基於時鐘的序列號的握手機制。

1.5.6 優先順序和安全性

使用者可以指定通訊的安全性和優先順序。

2. 基本原理(PHILOSOPHY)

2.1 網際網路絡系統的組成部分

網際網路絡環境由連在網路上的主機以及通過閘道器互聯的網路組成。
程式間通訊系統需要主機、網路、閘道器上各級協議的支援,並在程式埠間的邏輯連線(例如:TCP)上提供雙向的資料流。
每個程式都可以有幾個埠,程式通過埠區分彼此以及互相通訊。

  1. 程式:被視為主機的中活動的元素。
  2. 程式間通訊:如果終端、檔案、I/O裝置通過程式進行彼此通訊,也視為程式間通訊。
  3. 主機:連線到網路的計算機,從通訊網路的角度看,主機是資料包的源和目的地
  4. 網路:可以是本地網路(例如:乙太網)或大型網路(例如:CSTNET),都是基於分組轉換技術。
  5. 包:是TCP/IP協議通訊傳輸中的資料單位,一般也稱“資料包”。TCP不關心上層的資料結構。
  6. 邏輯連線:例如TCP連線。物理連線,例如網線連線。

2.2 執行方式

  +------------------------------------+
  |            higher-level            |
  +------------------------------------+
  |              TCP module            |
  +------------------------------------+
  |      internet protocol module      |
  +------------------------------------+
  |        network device driver       |
  +------------------------------------+
  |        communication network       |
  +------------------------------------+

TCP module -- TCP通訊模型:

  1. 程式使用緩衝區作為引數,將資料傳遞給TCP模組。
  2. TCP模組將快取中的資料打包成,呼叫 ip module 傳輸資料給目標TCP。
  3. 接收方TCP將資料從段中取出放入接受方緩衝區並通知接收方使用者。TCP段中的控制資訊(TCP頭)用於確保資料有序可靠的傳輸。

internet protocol module -- IP通訊模型:

  1. TCP呼叫ip模組
  2. ip模組將段封裝成internet資料包,ip頭部包含了目的ip模組或中間閘道器的路由資訊。
  3. ip模組將internet資料包封裝到區域網包中,例如MAC。呼叫網路卡驅動傳送資料。
  4. 包交換可以執行進一步的包裝,分片或者其它操作以投遞區域網到目的ip module
  5. 閘道器從它的區域網包中取出IP資料包,檢查並確定下一步路由。然後將IP資料包封裝到在適合於下一個網路的區域網包中,路由到下一個閘道器,或最終目的地
  6. 目的地ip模組將IP資料包展開成段,並將其傳遞給目的地TCP。

包交換器:應用了通訊技術,對分組的資料資訊進行程式處理的通訊裝置
區域網:區域網是一種私有網路,一般在一座建築物內或建築物附近,比如家庭、辦公室或工廠。
展開:將IP資料包重組成段

2.3 主機環境

假設作業系統中有個TCP模組。使用者訪問TCP就像訪問檔案系統一樣。TCP模組可能呼叫其他的作業系統功能。假設網路的實際介面由裝置驅動模組控制。TCP呼叫ip模組,該模組呼叫網路裝置驅動程式

TCP機制不排斥前端處理器實現。主機到前端協議必須支援本文描述的TCP/user介面的功能,見2.4

前端處理器:front end processor,FEP。也稱通訊控制器。例如:LVS 路由器 多路複用器。

2.4 介面

TCP介面分兩類:
TCP/user:提供給使用者或者應用程式使用
TCP/internet:TCP模組提供給底層協議(如IP協議)使用

TCP/user:開啟/關閉連線,傳送/接受資料,獲取連線狀態等功能。
TCP/internet:提供了從遠端(因特網上任意主機的TCP模組)傳送和接收資料包的功能。具有如下引數:傳遞地址、服務型別、優先順序、安全性和其他控制資訊。

2.5 與其他協議的關係

   +------+ +-----+ +-----+       +-----+
   |Telnet| | FTP | |Voice|  ...  |     |  Application Level
   +------+ +-----+ +-----+       +-----+
         |   |         |             |
        +-----+     +-----+       +-----+
        | TCP |     | RTP |  ...  |     |  Host Level
        +-----+     +-----+       +-----+
           |           |             |
        +-------------------------------+
        |    Internet Protocol & ICMP   |  Gateway Level
        +-------------------------------+
                       |
          +---------------------------+
          |   Local Network Protocol  |    Network Level
          +---------------------------+

                     Protocol Relationships

                           Figure 2.

2.6 通訊的可靠性

在TCP連線上傳送的資料流到達目的地後是有序,可靠的。

通過序列號和確認使傳輸變得可靠。資料每8bit(octet)分配一個序號。TCP頭部攜帶的序列號等於段中前8bit分配的序列號。確認號等於傳送方期望下一次收到的序列號。TCP傳輸一個包含資料的段時,將副本放入重傳佇列並啟動一個計時器;收到確認號後刪除副本。計時器結束前沒收到重傳。

    TCP A                                          TCP B
1.  ESTABLISHED --> <SEQ=100><DATA size=1460>  --> ESTABLISHED
2.  ESTABLISHED <-- <ACK=1561><CTL=ACK><DATA>  <-- ESTABLISHED
3.  ESTABLISHED --> <SEQ=1561><DATA size=1460> --> ESTABLISHED

http://c.biancheng.net/view/2352.html

TCP確認並不保證資料已經交付給使用者了。以bio為例:

+------------------------+
|使用者空間  使用者空間緩衝區  |
+------------------------+
|核心空間  套接字緩衝區    |
+------------------------+
|          network       |
+------------------------+
如上圖,資料到達接收方TCP,TCP檢查收到的資料塊和TCP頭部內容,判斷資料是否有丟失,沒有問題返回確認。然後將資料暫存到套接字緩衝區,並將資料按順序連線還原出原始資料,最後將資料交給應用程式。

//TODO nio是對上述流程帶來的影響?

為了控制TCPs之間的資料流量,採用了一個流量控制機制。接收方TCP會向傳送方TCP報告一個“視窗”。視窗代表接收方能接收的位元組大小。

2.7. 連線建立和清除

問:如何標識獨立的資料流?
答:套接字是網路上是唯一標識,由ip地址和tcp提供的埠組成。連線由兩端的一對套接字組成(本地ip 本地port 外部ip 外部port)。一條連線可以雙向傳輸,稱為“全雙工”。TCPs可以選擇任意的port和程式進行關聯。

在任何實現中有些必須的基本概念:
套接字:連線埠號和程式。程式可以擁有埠號,並在埠上啟動連線。
連線:由呼叫OPEN時傳入的引數(本地埠,外部套接字)決定。TCP會返回一個本地連線名稱,使用者通過它在隨後的呼叫中引用連線。一種實現策略,將本地連線名稱設定為指向TCB的指標。
TCB:Transmission Control Block,用於儲存連線的控制資訊。
OPEN:OPEN呼叫會指定連線建立是主動進行,還是被動等待。

passive OPEN:如果程式希望為其他程式提供服務,可以使用passive OPEN請求,外部地址使用0.0.0.0:0表示套接字尚未被指定。未指定的套接字只允許出現於passive OPEN。對應的連線狀態為Listener

對於 local passive OPENs 和 foreign active OPENs 的匹配規則主要有兩種情況。第一,local passive OPENs 指定了外部套接字時需精準匹配。第二,local passive OPENs 沒指定外部套接字,任意外部套接字都能接受。其它可能的情況包括部分嚴格匹配。

foreign socket: 0.0.0.0:0
0表示任意,不做限制。
如果不為0,需要精確匹配。

建立連線的過程使用同步(SYN)控制標誌,涉及“三次握手”。當序列號在兩個方向上同步完成,連線就建立了。連線的清除涉及段的交換,段會攜帶帶有FIN的控制標誌。

2.8 資料通訊

連線上的資料流是8bit流。傳送使用者在呼叫SEND函式可以通過標誌位PUH立即傳送資料。

傳送方TCP允許從使用者處先收集資料等到方便時再封裝到段裡傳送,收到push函式,必須傳送所有未傳送資料。當接收方TCP看到PSH標誌,馬上將資料轉交給接收程式。

TCP定義了緊急資料。TCP沒有規定收到緊急資料應該做什麼,一般情況下,接收程式應該儘快處理緊急資料。

2.9 安全和優先順序

TCP利用internet協議的服務欄位和安全選項,為TCP使用者提供基於每個連線的優先順序和安全性。
當TCP工作於多級安全環境下,需要提供安全和優先順序的選項。大部分TCP的實現是多級安全環境的一個子集。
在多級安全環境中執行的TCP模組必須正確標記出安全段、分隔段和優先順序。還必須向其使用者或更高階別的協議(如Telnet或THP)提供介面,用於指定安全級別、間隔和連線的優先順序。

2.10 魯棒性原則

TCP實現將遵循健壯性的一般原則: 自己做的事情上要謹慎,從別人那裡接受的事情上要自由(容錯)。
be conservative in what you do, be liberal in what you accept from others.

3. 功能規格

3.1 頭部格式

TCP段作為internet資料包傳送。IP報頭包含幾個訊息頭(源主機地址和目標主機地址)。TCP報頭跟在internet報頭後面。

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Sequence Number: 序列號 32 bits

這個段的第一個資料位元組的序列號(出現*SYN控制位*時除外)。 如果存在SYN,序列號代表初始序列號(ISN),第一個資料位元組是ISN+1。  

Acknowledgment Number: 確認號 32 bits

如果設定了*ACK控制位*,確認號=接收方期待的下一個收到的序列號。

Data Offset: 資料偏移量 4 bits

標識資料從哪裡開始

Control Bits: 控制位 6 bits (從左到右):

URG:  緊急標識
ACK:  確認標識
PSH:  立即傳送
RST:  重置連線
SYN:  同步序列號
FIN:  沒有更多的資料需要傳送了

Window: 視窗 16 bits

攜帶視窗的段的傳送方願意接受的資料位元組數

Checksum: 校驗和 16 bits

16位元組 = 偽首部12位元組,校驗和4位元組

首先是偽首部:源地址,目標地址,預留空間,傳輸層協議號(TCP是6)、TCP報文長度(報頭+資料)
                     +--------+--------+--------+--------+
                     |           Source Address          |
                     +--------+--------+--------+--------+
                     |         Destination Address       |
                     +--------+--------+--------+--------+
                     |  zero  |  PTCL  |    TCP Length   |
                     +--------+--------+--------+--------+
最後計算校驗和,校驗和計算方式:將TCP段以16bit為單位相加,然後取反碼。

Urgent Pointer: 緊急指標 16 bits

緊急指標指向緊急資料在報文段中結束的位置

Options: 可選項 變長 //TODO 暫為793規定的可選項

資料結構:
| kind(1位元組) | length(1位元組) | info(n位元組) |

      Kind     Length    Meaning
      ----     ------    -------
       0         -       End of option list.
       1         -       No-Operation
       2         4       最大分段大小.

      End of Option List

        +--------+
        |00000000|
        +--------+
         Kind=0
表示可選項列表結束

      No-Operation

        +--------+
        |00000001|
        +--------+
         Kind=1
在可選項之間使用,佔一位元組,用於選項間填充資料,做對齊。

      MSS:最大分段大小
      +--------+--------+---------+--------+
      |00000010|00000100|   max seg size   |
      +--------+--------+---------+--------+
      Kind=2   Length=4
最大分段大小,只在連線初始化時使用。接收方用它來告訴傳送者,我期望的最大分段大小是多少。

Padding: 填充 變長

確保TCP頭部長度為32bit的整數倍。

3.2 術語

討論TCP操作之前,需要詳細的介紹一些術語。這些術語大致分為2部分:

  1. TCB:Transmission Control Block 傳輸控制塊
  2. 當前段(segment)相關變數
  3. 連線的生命週期中經歷的一系列狀態

3.2.1 TCB

維護TCP連線需要記錄一些變數,這些變數被儲存在TCB中。
儲存在TCB中的變數包括:

  1. 本地和遠端套接字編號
  2. 連線的安全性和優先順序
  3. 指向使用者傳送和接收緩衝區的指標
  4. 指向重傳佇列和指向當前段的指標
  5. 與傳送和接收序列號相關的幾個變數

傳送序列號相關的變數


SND.UNA - 已傳送 未經確認
SND.NXT - 傳送方 下一個要傳送的序列號
SND.WND - 傳送視窗
SND.UP -  傳送緊急指標
SND.WL1 - 上次視窗更新的時段系列號(segment sequence number used for last window update)。傳送方收到接收方返回的視窗,觸發視窗更新時會儲存一個段序列號
SND.WL2 - 用於上次視窗更新的段確認號(segment acknowledgment number used for last Window update)。傳送方收到接收方返回的視窗,觸發視窗更新時會儲存一個段確認號
ISS - 初始傳送系列號,三次握手階段使用

  傳送序列空間,傳送視窗即圖4第三部分

                   1         2          3          4
              ----------|----------|----------|----------
                     SND.UNA    SND.NXT    SND.UNA
                                          +SND.WND

        1 - 已傳輸資料已收到確認的舊序列號
        2 - 已傳輸資料未收到確認資料的序列號
        3 - 當前允許用於傳輸資料但還未傳輸的序列號
        4 - 當前不允許傳輸的將來的系列號

                               Figure 4.

接收序列號相關的變數

      RCV.NXT - 接收下一個
      RCV.WND - 接收視窗
      RCV.UP  - 接收緊急指標
      IRS     - 初始化接收序列號

  接收序列空間, 接收視窗即圖5第2部分。

                       1          2          3
                   ----------|----------|----------
                          RCV.NXT    RCV.NXT
                                    +RCV.WND

        1 - 已確認的舊序列號
        2 - 允許接收的新序列號
        3 - 不允許接收的未來序列號
        
                               Figure 5.
    

3.2.2 當前段(segment)相關變數

討論中還經常使用一些變數,它們的值來自當前段的變數。

當前段變數

      SEG.SEQ - 段序列號
      SEG.ACK - 段確認號
      SEG.LEN - 段長度
      SEG.WND - 段視窗
      SEG.UP  - 段緊急指標
      SEG.PRC - 段優先順序欄位

3.2.3 連線的生命週期中經歷的一系列狀態

一個連線在其生命週期中會經歷一系列的狀態:

建立連線
LISTEN、SYN-SENT、SYN-RECEIVED、
連線中
ESTABLISHED
斷開連線
FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT
不在連線狀態
CLOSED

CLOSED是虛構的,表示沒有任何連線狀態,TCB不存在。

狀態機


                              +---------+ ---------\      active OPEN
                              |  CLOSED |            \    -----------
                              +---------+<---------\   \   create TCB
                                |     ^              \   \  snd SYN
                   passive OPEN |     |   CLOSE        \   \
                   ------------ |     | ----------       \   \
                    create TCB  |     | delete TCB         \   \
                                V     |                      \   \
                              +---------+            CLOSE    |    \
                              |  LISTEN |          ---------- |     |
                              +---------+          delete TCB |     |
                   rcv SYN      |     |     SEND              |     |
                  -----------   |     |    -------            |     V
 +---------+      snd SYN,ACK  /       \   snd SYN          +---------+
 |         |<-----------------           ------------------>|         |
 |   SYN   |                    rcv SYN                     |   SYN   |
 |   RCVD  |<-----------------------------------------------|   SENT  |
 |         |                    snd ACK                     |         |
 |         |------------------           -------------------|         |
 +---------+   rcv ACK of SYN  \       /  rcv SYN,ACK       +---------+
   |           --------------   |     |   -----------
   |                  x         |     |     snd ACK
   |                            V     V
   |  CLOSE                   +---------+
   | -------                  |  ESTAB  |
   | snd FIN                  +---------+
   |                   CLOSE    |     |    rcv FIN
   V                  -------   |     |    -------
 +---------+          snd FIN  /       \   snd ACK          +---------+
 |  FIN    |<-----------------           ------------------>|  CLOSE  |
 | WAIT-1  |------------------                              |   WAIT  |
 +---------+          rcv FIN  \                            +---------+
   | rcv ACK of FIN   -------   |                            CLOSE  |
   | --------------   snd ACK   |                           ------- |
   V        x                   V                           snd FIN V
 +---------+                  +---------+                   +---------+
 |FINWAIT-2|                  | CLOSING |                   | LAST-ACK|
 +---------+                  +---------+                   +---------+
   |                rcv ACK of FIN |                 rcv ACK of FIN |
   |  rcv FIN       -------------- |    Timeout=2MSL -------------- |
   |  -------              x       V    ------------        x       V
    \ snd ACK                 +---------+delete TCB         +---------+
     ------------------------>|TIME WAIT|------------------>| CLOSED  |
                              +---------+                   +---------+

                      TCP Connection State Diagram
                               Figure 6.

3.3 序列號

設計TCP時有個基礎概念:TCP連線上每8bit資料都會分配一個序列號。
由於資料流每八位分配一個序號,所以沒有序號都可以用來確認,確認號X代表X之前的序號都已確認,但不包括X。這種機制可用於重傳。緊跟在頭後面的第一個8bit是最低序號,接下來的8bit是連續序號。

序號是int型,取值範圍 0 ~ 2^32-1(42,9496,7296) == 4G. 對於溢位的數值,計算機做取模操作。

幾種典型的TCP必須處理的序列號型別:

(a) 序列號已傳送,但未確認
(b) 段中的序列號已確認,從重傳佇列中移除段
(c) 接收到的段中包含符合預期的序列號(是否在接收視窗範圍內)。

TCP接收到資料進行確認時,進行以下比較

SND.UNA = 最大未確認序列號
SND.NXT = 下一個傳送序列號
SEG.ACK = 接收方TCP最大確認號 (接收TCP所期望的下一個序列號)
SEG.SEQ = 段的第一個序列號
SEG.LEN = 段中資料佔用的位元組數(包括SYN和FIN)
SEG.SEQ+SEG.LEN-1 = 段的最後序列號

SND.UNA < SEG.ACK =< SND.NXT
如果重傳佇列上的段的序列號和長度之和小於或等於傳入段中的確認值,則該段被完全確認

當接收資料時需要做以下比較:

RCV.NXT = 預期接收到的下一個段的序列號,在接收視窗的範圍內    RCV.NXT+RCV.WND-1 = 預期接收到的段的序列號最大值
SEG.SEQ = 傳入段的佔用的第一個序列號
SEG.SEQ+SEG.LEN-1 = 傳入段佔用的最後一個序列號

    Segment Receive  Test
    Length  Window
    ------- -------  -------------------------------------------

       0       0     SEG.SEQ = RCV.NXT

       0      >0     RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND

      >0       0     not acceptable

      >0      >0     RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
                  or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND

ISN(初始序列號)
// TODO 為什麼ISN是一個隨機數以及它的隨機演算法?

傳送的每個段會佔用序列空間中的一個多個序列號,被段佔用的號碼都是“busy”或“in use”狀態直到經過MSL秒(maximun segment lifetime)。

3.4 建立連線

  TCP A                                                TCP B
1.  CLOSED                                               LISTEN
2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               --> SYN-RECEIVED
3.  ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED
4.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK>       --> ESTABLISHED
5.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED

                      三次握手
                    Figure 7.

  TCP A                                            TCP B
1.  CLOSED                                           CLOSED
2.  SYN-SENT     --> <SEQ=100><CTL=SYN>              ...
3.  SYN-RECEIVED <-- <SEQ=300><CTL=SYN>              <-- SYN-SENT
4.               ... <SEQ=100><CTL=SYN>              --> SYN-RECEIVED
5.  SYN-RECEIVED --> <SEQ=100><ACK=301><CTL=SYN,ACK> ...
6.  ESTABLISHED  <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
7.               ... <SEQ=101><ACK=301><CTL=ACK>     --> ESTABLISHED

                    同時發起連線
                      Figure 8.
  TCP A                                                TCP B
1.  CLOSED                                               LISTEN
2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               ...
3.  (duplicate) ... <SEQ=90><CTL=SYN>               --> SYN-RECEIVED
4.  SYN-SENT    <-- <SEQ=300><ACK=91><CTL=SYN,ACK>  <-- SYN-RECEIVED
5.  SYN-SENT    --> <SEQ=91><CTL=RST>               --> LISTEN
6.              ... <SEQ=100><CTL=SYN>               --> SYN-RECEIVED
7.  SYN-SENT    <-- <SEQ=400><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED
8.  ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK>      --> ESTABLISHED
                    Recovery from Old Duplicate SYN
                               Figure 9.
  TCP A                                           TCP B
1.  (CRASH)                               (send 300,receive 100)
2.  CLOSED                                           ESTABLISHED
3.  SYN-SENT --> <SEQ=400><CTL=SYN>              --> (??)
4.  (!!)     <-- <SEQ=300><ACK=100><CTL=ACK>     <-- ESTABLISHED
5.  SYN-SENT --> <SEQ=100><CTL=RST>              --> (Abort!!)
6.  SYN-SENT                                         CLOSED
7.  SYN-SENT --> <SEQ=400><CTL=SYN>              -->
                     半連線
                     Figure 10.

// TODO 半連線與RST