TCP連線關閉總結

2021-07-01 23:45:30 字數 2638 閱讀 8556

由於涉及面太廣,只作簡單整理,有興趣的可參考《unix networking programming》volum 1, section 5.7, 5.12, 5.14, 5.15, 6.6 以及7.5 so_linger選項。

以乙個簡單的echo伺服器為例,客戶端從標準輸入讀入字元,傳送給伺服器,伺服器收到後再原樣返回,客戶端收到後列印到標準輸出。

那麼,關於套接字的關閉有以下幾種情形:

1,客戶端關閉連線:

1.1,客戶端呼叫close()

1.2,客戶端程序關閉

1.3,客戶端呼叫shutdown()

1.4,客戶端呼叫close()+so_linger選項

1.5,客戶端崩潰

2,伺服器關閉連線:

2.1,伺服器呼叫close()

2.2,伺服器程序關閉

2.3,伺服器崩潰

2.4,伺服器崩潰+so_keepalive選項

****************************************分割線****************************************=

1.1與1.2等價,就算客戶端程序關閉,系統核心也會自動close(socket),且注意,當socket引用為0時才會真正呼叫close(),close()總是立即返回的,然後由系統嘗試傳送完核心緩衝區內的所有資料,接著才傳送fin。

說道這裡,不得不談談tcp連線關閉的四次握手。可以看成是2組fin, ack。主動關閉的一方先傳送fin,收到ack後,進入fin_wait2狀態,此時也叫做「半關閉」狀態,特別須要注意的是,此時客戶端套接字依然可以接收資料報,但是不能傳送資料報。 被動關閉的一方,此時收到fin了,一般情況下都是由於read(socket)返回0,然後得知對方關閉,close(socket)後,另外一組fin,ack隨之產生,此時主動方進入time_wait狀態。即四次握手完成。

以上即是正常情況下連線關閉的情形。

再看看1.3,shutdown()與close()主要有3點區別:

shutdown()不理會引用計數與核心緩衝區內剩餘待發資料報,直接傳送fin;

shutdown()可以只關閉套接字某個方向的連線,例如關閉傳送,關閉接收,或者2者都關閉;

實際上shutdown(write)後,就是上面說的半關閉情形,依然可以完成四次握手。

再看看1.4,為什麼要設定so_linger呢

so_linger的目的就是改變close()的預設行為,可以決定close()在哪個狀態返回,或者讓套接字立即傳送rst,從而沒有fin的傳送。接收方返回econnreset錯誤,連線直接關閉。

再來總結下1.1-1.4,這麼多關閉連線的方式,那麼什麼方式才是最好的呢?

擇優選擇的方式當然是考慮最惡劣的情況,對方主機崩潰或網路故障導致資料報傳輸停滯。

rst不用考慮了,直接time_wait狀態都沒,如果有網路故障,可能下次建立的套接字還會接收到已經被銷毀的套接字的資料報。

close()不能保證對方一定收到fin。

close()+so_linger雖然能控制close()在收到ack後返回,依然不能保證四次握手完成。

shutdown()先進入半關閉狀態,再呼叫read(),返回0(收到對方fin)則說明四次握手正常進行,此為最優方式。

其實仔細想想,一般情況也不用這麼麻煩,拿網遊伺服器來說,客戶端close()後,就算伺服器不知道,那麼這種情況歸為1.5討論;如果是服務端close()而客戶端不知道,那麼歸為2.3討論。總之都有解決辦法。。

現在再討論1.5,很簡單,服務端加入鏈路異常檢測機制即可,這也是所有大型tcp伺服器必備的機制,定時傳送小資料報檢測客戶端是否有異常退出。

****************************************分割線****************************************=

伺服器關閉連線方面:

2.1,2.2等價,一般情況下也與1.1,1.2等價,只是主動關閉方是伺服器了。

但是,在我們討論的例子裡,客戶端要從標準輸入讀字元,這是阻塞方式,服務端關閉連線後,客戶端無法知道,因為它阻塞在標準輸入了,當我們再次輸入字元,並傳送,收到fin或rst,此時客戶端才關閉。總之,客戶端由於某種原因,不能及時呼叫read(),所以無法得知伺服器關閉了連線。

2.3,伺服器崩潰,客戶端由於一直收不到ack,會一直嘗試傳送資料,標準socket大概是9分鐘後才會返回錯誤。

2.3,伺服器崩潰,客戶端又長時間與伺服器沒有資料互動,此時設定so_keepalive選項可得知。

****************************************分割線****************************************=

後記:網路是門複雜的學問,由此tcp連線的關閉可見一斑。普通程式設計師通常不會考慮這麼細緻,但是我相信這些問題一直困擾著他們。

補充說明:經試驗,在windows平台,1.2  2.2情況等同於close()+so_linger選項直接傳送rst,可能由於系統必須及時清理資源吧,這點與linux是不同的,有興趣的可以試試。。

TCP連線關閉過程筆記

tcp協議的連線是全雙工連線,乙個tcp連線存在雙向的讀寫通道。簡單說來是 先關讀,後關寫 一共需要四個階段。以客戶機發起關閉連線為例 1.伺服器讀通道關閉 2.客戶機寫信道關閉 3.客戶機讀通道關閉 4.伺服器寫信道關閉 關閉行為是在發起方資料傳送完畢之後,給對方發出乙個fin finish 資料...

TCP連線關閉過程筆記

前言 tcp協議的連線是全雙工連線,乙個tcp連線存在雙向的讀寫通道。簡單說來是 先關讀,後關寫 一共需要四個階段。以客戶機發起關閉連線為例 1.伺服器讀通道關閉 2.客戶機寫信道關閉 3.客戶機讀通道關閉 4.伺服器寫信道關閉 關閉行為是在發起方資料傳送完畢之後,給對方發出乙個fin finish...

ubuntu中gedit 連線關閉問題

今天遇到乙個問題,開始不知道怎麼回事,特意上網查詢下,記錄如下 使用gedit命令之後出現如下警告 gedit 6577 warning the connection is closed gedit 6577 warning could not connect to session bus 原因是 ...