四次揮手與Socket API

在《三次握手與Socket API》中咱們詳細講解了三次握手以及與之相關的API,三次握手是TCP協議的初始階段,用來創建雙方通訊鏈接,顯然有創建鏈接就有斷開鏈接,那麼TCP是如何斷開鏈接的呢?程序員

奇怪的四次揮手

TCP協議創建鏈接須要進行三次信息交互,斷開鏈接時卻須要四次信息交互,這四次信息交互被形象的稱爲四次揮手,那麼TCP在斷開鏈接時爲何須要奇怪的四次揮手而不是三次揮手呢?要想回答這個問題咱們必須對TCP協議有進一步的理解。編程

話多的人與話少的人

生活中總會有這兩類人,一類話多,一類話少,話少的那個言簡意賅很快就無話可說了,話多的那個口若懸河沒完沒了,所以就會有這樣的情形:服務器

A: 今每天氣這不錯啊
A: 今天飯也好吃
A: 是吧
                   是的 :B
                我說完了 :B
A: 我還沒說完呢
A: 明天就週五啦
A: 開心
A: blablabla
A: 我也說完了

當這兩類人在聊天時就會出現B說完但A沒說完的狀況,這時B再也不說話可是能夠繼續聽A說,當A也說完後整個聊天過程纔算結束。微信

TCP通訊過程和人聊天又有多大區別呢?網絡

有話多話少的人固然也會有數據多數據少的客戶端以及服務器。socket

爲何要四次揮手:半關閉

在TCP通訊中一方表示「我說完了」其實是經過向對方發送一條帶有FIN標識的消息來實現的,當一方收到FIN信息時就知道接下來對方就不會再發送數據了,這在TCP協議中被稱爲半關閉,half-close。函數

TCP爲何要支持半關閉呢?爲何不是一方說完你們都閉嘴呢?spa

原來TCP通訊和兩我的聊天是同樣的,你在說話的同時也在聽,也就是說你能夠同時收發信息,這就是所謂的全雙工通訊,在這種通訊方式下你說完了不表明對方也說完了,所以只有雙方都說完了鏈接才能徹底關閉。操作系統

TCP也是全雙工通訊,TCP規定通訊的任意一方均可以向對方發送FIN信息(表示我說完了),但這也僅僅表示一方沒什麼要發送的了,但這並不影響對方繼續發送數據(對方還沒發送完數據)。3d

這就是爲何TCP支持半關閉的緣由,半關閉的本質就是TCP通訊中一方已經沒什麼數據要發送了,雖然沒有數據要發送但還能夠繼續接收數據

四次揮手的過程

理解了前幾節接下來就簡單啦,假設有一個話少的客戶端和一個話多的服務器端就會有以下情形:
圖片描述
從圖中咱們能夠看出雖然客戶端發送了FIN信息但此時服務器端還有數據要發送,所以服務器端沒有理會客戶端發送的FIN而是繼續發送數據直到服務器端也發送完,此時服務器端發送FIN表示數據發送完畢,客戶端接收到消息後進行ACK回覆,這時TCP鏈接才真正斷開。

不過值得注意的是,做爲程序員在網絡編程中咱們幾乎不會遇到上述情形,一般客戶端向服務器端發送FIN後服務器端就不會再向客戶端繼續發送數據了,通常狀況下TCP通訊的整個過程都是客戶端來主導的,客戶端主動發起鏈接,獲取到想要的信息後主動斷開鏈接,服務器端只是被動同客戶端創建連接,客戶端想要什麼服務器端通過處理後就返回給客戶端什麼,當客戶端不想再聊天時服務器端也不會還在口若懸河,總而言之,客戶端與服務器就比如用戶和客服同樣,整個過程都是用戶來主導的,客服只是被動的來回答問題,當用戶沒什麼問題後沒有哪一個客服還會繼續和用戶聊下去,固然客服讓用戶給好評除外,放心,服務器端是不須要客戶端給好評的 :) ,所以咱們一般看到的這樣的情形:
圖片描述
有的同窗可能會想,爲何B發送的ACK和FIN不能和三次握手同樣合併成一次呢?就像這樣:
圖片描述
若是隻有三次揮手那麼TCP就沒有辦法支持半關閉了,三次揮手實際是在說「若是有一方閉嘴那麼咱們都閉嘴」,雖然做爲程序員咱們在網絡編程時遇到的都是這種情形,可是從TCP協議層面來講應該支持半關閉,也就是支持通訊雙方中一個話多一個話少的情形。

如今你應該明白爲何要四次揮手而不能是簡單的三次了吧。
四次揮手與close
和三次握手同樣,四次揮手也有與之相對應的API,這樣的API有兩個,一個是咱們經常使用的close,另外一個是shutdown。

close是咱們最常使用的一個,既然close是最經常使用的,那麼close也就用在「一方閉嘴你們都閉嘴」的情形,如圖所示:
圖片描述

咱們已經知道四次揮手一般是由客戶端來發起的,當客戶端執行close函數後會向服務器端發出FIN消息,服務器端操做系統接收到該信息後向服務器進程發出EOF(end of file),這時服務器不管調用send仍是recv都會失敗,此時服務器端認爲客戶端已經關閉了鏈接,所以調用close函數關閉同客戶端的鏈接,當客戶端接收到FIN信息後進行ACK回覆確認,整個四次揮手的過程完畢。

四次揮手與shutdown:半關閉
客戶端和服務器使用close來完成四次揮手是最多見的過程,即「一方閉嘴你們都閉嘴」,咱們知道做爲全雙工通訊協議的TCP還須要支持半關閉,也就是說一方說完但另外一方還在說的場景,這時先說完的就只能聽了,做爲程序員咱們須要知道幾乎沒有什麼應用場景要用到TCP提供的半關閉能力。

當客戶端調用close後若是服務器端沒有理會而是繼續向客戶端發數據,那麼此時客戶端是接收不到的,固然這就是客戶端調用close函數的目的。

而若是客戶端表示:「我沒什麼要說的了,因此要向服務器發送FIN,可是我還想聽服務器囉嗦一下子直到對方也說完」該怎麼辦呢?這時客戶端就不能調用close了而是應該調用socket提供的另外一個API,也就是shutdown,典型的場景如圖所示:
圖片描述

雖然客戶端調用shutdown向服務器端發送了FIN表示本身說完了,可是服務器端仍是能夠繼續向客戶端發送任意多的數據,而客戶端依然能夠接收到數據,直到服務器端也發送FIN消息客戶端回覆ACK確認後鏈接纔算是真正關閉。

如今你應該明白如何使用shutdown利用TCP的半關閉能力了吧。

總結

本文是繼《三次握手與Socket API》的第二篇,講述了四次揮手的過程以及爲何須要四次揮手,之因此須要四次揮手是由於TCP協議須要提供一種被稱爲半關閉的能力,可是不多有應用場景須要依賴該能力。做爲程序員咱們須要知道大部分狀況下使用close就能夠完成四次揮手,可是若是須要依賴TCP提供的半關閉能力那麼須要使用另外一個API,也就是shutdown。

若是你喜歡這一系列的文章,也歡迎關注個人微信公共帳號,碼農的荒島求生,獲取更多內容。

clipboard.png

計算機內功決定程序員職業生涯高度
相關文章
相關標籤/搜索