[TOC]
## 6、為什么需要TIME_WAIT
### 一、何為TIME_WAIT?
我們在日常做服務器的研發中、或者面試網絡部分知識的時候,會經常問到TIME_WAIT這個詞,這個詞作為服務端的開發者尤為重要。TIME_WAIT是TCP協議中斷開連接所經歷的一種狀態。

? 上圖是TCP連接的狀態轉換,包括了一些觸發條件,如果不是很直觀,可以對比看下面的簡圖。

? 這里面作為主動關閉的一方(Client)出現了`TIME_WAIT`狀態,目的是告訴Server端,**自己沒有需要發送的數據**,但是它仍然**保持了接收對方數據的能力**,一個常見的關閉連接過程如下:
1、當客戶端沒有待發送的數據時,它會向服務端發送 `FIN` 消息,發送消息后會進入 `FIN_WAIT_1` 狀態;
2、服務端接收到客戶端的 `FIN` 消息后,會進入 `CLOSE_WAIT` 狀態并向客戶端發送 `ACK` 消息,客戶端接收到 `ACK` 消息時會進入 `FIN_WAIT_2` 狀態;
3、當服務端沒有待發送的數據時,服務端會向客戶端發送 `FIN` 消息;
4、客戶端接收到 `FIN` 消息后,會進入 `TIME_WAIT` 狀態并向服務端發送 `ACK` 消息,服務端收到后會進入 `CLOSED` 狀態;
5、客戶端等待**兩個最大數據段生命周期**(Maximum segment lifetime,MSL)的時間后也會進入 `CLOSED` 狀態;
---
### 二、為什么需要TIME_WAIT
**TIME_WAIT一定是發生在主動關閉一方**
被動關閉一方,會直接進入`CLOSED`狀態,而主動關閉一方需要等待2*MSL時間才會最終關閉。
原因:
1、防止被動關閉方的延遲數據被人竊取
2、防止被動關閉方沒有收到最后的ACK
#### 原因一:防止被動關閉方的延遲數據被人竊取

如上圖所示,
1、在①中,服務端發送`seq=1001`的消息,由于網絡延遲或其他原因,沒有及時到達`Client1`客戶端,導致整個包一直存留在網絡環境的傳輸過程中。
2、在②中,`Client1`收到server的`FIN`包之后,變成了`TIME_WAIT`狀態,這里假設`TIME_WAIT`等待的時間很短暫,那么,還沒等之前的那個延遲包`seq=1001`到來,就回復給了`Server`最后一個`ACK`包。那么`Server`就會變成`CLOSED`狀態。
3、在③中,相同的端口號的`Client2`的TCP鏈接被重用后
4、在④中,`seq=1001`的延遲包消息才發送給客戶端,而這個延遲的消息卻被`Client2`正常接收,主要就會給Client2帶來嚴重的問題。所以`TIME_WAIT`不要輕易的調整,或者縮小時間,可能就會出現這種問題。
#### 原因二:防止被動關閉方沒有收到最后的ACK
? 該作用就是等待足夠長的時間以確定遠程的TCP鏈接收到了其發出的終止鏈接消息`FIN`包的回執消息`ACK`包。

? 如上圖所示:
1、在①中,`CLient1`端主動發起關閉鏈接,`Server`針對`Client1`的`FIN`回執了`ACK`包,然后接著發送了自己的`FIN`包,等待`Client1`回執最終的`ACK`包。
2、在②中,這里假設`TIME_WAIT`的時間不足夠充分,當`Server`還沒有收到 `ACK` 消息時,`Client1`就主動變成`CLOSED`狀態。
3、在③中,由于`Server`一直沒有等到自己`FIN`包的`ACK`應答包,導致一直處于`LAST_ACK`狀態。
4、在④中,因為 服務端因為沒有收到 `ACK` 消息,當`Client2`重新與`Server`建立TCP鏈接,認為當前連接是合法的,`CLient2`重新發送 `SYN` 消息請求握手時會收到`Server`的 `RST` 消息,連接建立的過程就會被終止。
所以,我們在默認情況下,如果客戶端等待足夠長的時間就會遇到以下兩種情況:
1. 服務端正常收到了 `ACK` 消息并關閉當前 TCP 連接;
2. 服務端沒有收到 `ACK` 消息,重新發送 `FIN` 關閉連接并等待新的 `ACK` 消息;
只要客戶端等待 2 MSL 的時間,客戶端和服務端之間的連接就會正常關閉,新創建的 TCP 連接收到影響的概率也微乎其微,保證了數據傳輸的可靠性。
- 封面
- 第一篇:Golang修養必經之路
- 1、最常用的調試 golang 的 bug 以及性能問題的實踐方法?
- 2、Golang的協程調度器原理及GMP設計思想?
- 3、Golang中逃逸現象, 變量“何時棧?何時堆?”
- 4、Golang中make與new有何區別?
- 5、Golang三色標記+混合寫屏障GC模式全分析
- 6、面向對象的編程思維理解interface
- 7、Golang中的Defer必掌握的7知識點
- 8、精通Golang項目依賴Go modules
- 9、一站式精通Golang內存管理
- 第二篇:Golang面試之路
- 1、數據定義
- 2、數組和切片
- 3、Map
- 4、interface
- 5、channel
- 6、WaitGroup
- 第三篇、Golang編程設計與通用之路
- 1、流?I/O操作?阻塞?epoll?
- 2、分布式從ACID、CAP、BASE的理論推進
- 3、對于操作系統而言進程、線程以及Goroutine協程的區別
- 4、Go是否可以無限go? 如何限定數量?
- 5、單點Server的N種并發模型匯總
- 6、TCP中TIME_WAIT狀態意義詳解
- 7、動態保活Worker工作池設計