串連的三向交握
- 用戶端向伺服器發送SYN請求
- 伺服器發送ACK回應請求,並同時發送一個SYN的請求給用戶端
- 用戶端回應ACK應答
關閉的四次握手
對於關閉流程,一共有三種情況:用戶端主動關閉,伺服器端主動關閉,用戶端和伺服器端同時主動關閉。這裡僅僅以用戶端主動關閉為例列出。
- 用戶端主動關閉,發送FIN請求
- 伺服器回應ACK應答
- 伺服器被動關閉,發送FIN請求
- 用戶端回應ACK應答
對於關閉流程,伺服器端和用戶端是對等的地位,其它兩種情境處理過程類似。需要注意的是,由於對端是是可以主動關閉的,因此在代碼中需要加上被動關閉的響應流程。
為什麼串連和關閉握手次數不一樣
看到上述流程,可能有一個疑問:為什麼串連和關閉的握手次數不一樣?其實,不論是串連還是關閉,用戶端和伺服器端都是發送了一次請求(SYN/FIN),回應了一次應答(ACK),它們是對稱的。但是,在串連的時候伺服器端的請求和應答是在一次握手中同時完成的,而關閉的時候卻是分兩次完成的,所以就造成了串連和關閉的握手次數不對稱。
現在,新問題又來了:為什麼串連時複用一次握手,而關閉的時候不複用握手?這個則是因為串連和關閉的行為不是一樣所造成的。
- 在串連過程中,用戶端是主動串連,伺服器端是被動串連,這個順序是確定了的,因此,可以複用第二次握手。
- 在關閉的過程中,用戶端和伺服器端可能同時主動關閉,此時就不能複用第二次握手了,因此請求和應答需要單獨的發送。
Tcp串連的狀態遷移圖
前面只考慮了理想的情況,在實際的過程中,可能還需要處理一些異常操作,如下則是一個完成的TCP串連的狀態遷移圖。
半開啟串連和半關閉串連
如前所述,建立或關閉一個串連時需要三或四步的,在這個過程中,TCP串連則會處於一個半開啟或半關閉狀態。例如,前面狀態圖中的FIN_WAIT_1和FIN_WAIT_2就是半關閉狀態。
一般來說,半串連只是一個暫停過程。但是,在一些異常的情況的時候(如遠端主機故障)的時候常常會造成半關閉串連,由於Tcp串連處於半開啟或半關閉狀態的時候,仍然會佔用相應的連接埠資源,尤其對於http之類的海量服務來說,會造成大量連接埠被佔用,會造成資源的浪費。
另外,有的程式也針對Tcp協議的這一特徵來惡意進行網路攻擊。例如,對於一個伺服器,大量的惡意用戶端建立串連後,既不發請求,也不close通訊端,這種情況下伺服器如何保護自己呢。因為如果聽之任之的話,大量的惡意串連會耗盡伺服器的可用描述符,導致伺服器不能服務。就算伺服器主動close,如果用戶端不close的話,那麼這個串連還是不能完全釋放。對於伺服器來說,需要增加相應的機制進行半串連的處理。