在前面的內容中我們介紹了TCP連接管理中最常見的三次握手方式和四次揮手的方式。但是有可能A和B兩端同時執行主動打開並連接對方或者同時執行主動關閉連接(盡管發生這種情況的可能性比較低低),這個時候的流程就略有不同了。下面我們分別對同時打開(simultaneous open)連接和同時關閉(simultaneous)連接這兩種情況分別進行介紹。
一、同時打開連接
同時打開連接是指通信的雙方在接收到對方的SYN包之前,都進行了主動打開的操作並發出了自己的SYN包。如之前所說一個四元組標識一個TCP連接,因此如果一個TCP連接要同時打開需要通信的雙方知曉對方的IP和端口信息才行,這種場景在實際情況中很少發生(NAT穿透中可能會多一些)。同時打開的流程如下圖

具體流程我們不在逐條消息進行介紹。注意上圖中,TCP連接同時打開的時候與三次握手的主要區別如下
- 我們同時稱呼A和B為Client,他們都執行主動打開的操作(Active Opener)。
- 同時兩端的狀態變化都是由CLOSED->SYN_SENT->SYN_RCVD->ESTABLISHED。
- 建立連接的時候需要四個數據包的交換,並且每個數據包中都攜帶有SYN標識,直到收到SYN的ACK為止
二、同時關閉連接
同時關閉相對於我們講過的四次握手過程基本類似,注意兩者狀態轉換的區別,同時關閉是由ESTABLISHED->FIN_WAIT_1->CLOSING->TIME_WAIT->CLOSED。同時關閉的流程如下,不在做額外的講解。

三、示例
1.tcp同開
由於linux實現不支持TCP同時主動打開連接,因此我們拿RFC793中的示意圖來舉例
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
Simultaneous Connection Synchronization
RFC793對示意圖中的相關符號說明如下,大家對照下面的說明仔細觀察一下上面RFC的文字示例圖,有沒有發現什么問題呢?(參看補充說明部分第2點)
Right arrows (-->) indicate
departure of a TCP segment from TCP A to TCP B, or arrival of a
segment at B from A. Left arrows (<--), indicate the reverse.
Ellipsis (...) indicates a segment which is still in the network
(delayed).
下面看一下wireshark實際抓包
2.tcp同關
linux本身也是支持TCP同時關閉連接的,wireshark抓包如下
3.tcp通過三次數據包交換關閉連接
還有一種場景是TCP通過三次數據包交換來關閉連接,這種場景同樣很少遇到,我們不做過多介紹,以一個wireshark實例來看一下相關的系列號seq和ack number的關系
補充說明
1、RFC793給的同時打開TCP連接的示意圖中,TCP B進入ESTABLISHED狀態前收到的包應該是<SEQ=100><ACK=301><CTL=SYN,ACK>。想借此提醒不要僅僅看協議本身,還要記得看協議是否由對應的勘誤表(errata)。原始的RFC793協議有很多
2、本篇文章給出的同時關閉時的tcp包時序圖是與RFC793一致的,但是注意一些資料包括我所參考的第二版 tcpip詳解,給的同時關閉的示意圖中最后兩條消息的系列號seq是錯誤的,或者干脆沒有給出系列號seq的值。



