從tcp協議角度來看,乙個已建立的tcp連線有兩種關閉方式,一種是正常關閉,即四次揮手關閉連線;還有一種則是異常關閉,我們通常稱之為連線重置(reset)。
首先說一下正常關閉時四次揮手的狀態變遷,關閉連線的主動方狀態變遷是fin_wait_1->fin_wait_2->time_wait,而關閉連線的被動方的狀態變遷是close_wait->last_ack->closed。在四次揮手過程中ack包都是協議棧自動完成的,而fin包則必須由應用層通過closesocket或shutdown主動傳送,通常連線正常關閉後,recv會得到返回值0,send會得到錯誤碼10058。
除此之外,在我們的日常應用中,連線異常關閉的情況也很多。比如應用程式被強行關閉、本地網路突然中斷(禁用網絡卡、網線拔出)、程式處理不當等都會導致連線重置,連線重置時將會產生rst包,同時網路絡緩衝區中未接收(傳送)的資料都將丟失。連線重置後,本方send或recv會得到錯誤碼10053(closesocket時是10038),對方recv會得到錯誤碼10054,send則得到錯誤碼10053(closesocket時是10054)。
作業系統為我們提供了兩個函式來關閉乙個tcp連線,分別是closesocket和shutdown。通常情況下,closesocket會向對方傳送乙個fin包,但是也有例外。比如有乙個工作執行緒正在呼叫recv接收資料,此時外部呼叫closesocket,會導致連線重置,同時向對方傳送乙個rst包,這個rst包是由本方主動產生的。
shutdown可以用來關閉指定方向的連線,該函式接收兩個引數,乙個是套接字,另乙個是關閉的方向,可用值為sd_send,sd_receive和sd_both。
方向取值為sd_send(outputstream)時,無論socket處於什麼狀態(recv阻塞,或空閒狀態),都會向對方傳送乙個fin包,注意這點與closesocket的區別。此時本方進入fin_wait_2狀態,對方進入close_wait狀態,本方依然可以呼叫recv接收資料;
方向取值為sd_receive時,雙方連線狀態沒有改變,依然處於established狀態,本方依然可以send資料,但是,如果對方再呼叫send方法,連線會被立即重置,同時向對方傳送乙個rst包,這個rst包是被動產生的,這點注意與closesocket的區別。
關閉TCP連線的學問
從tcp協議角度來看,乙個已建立的tcp連線有兩種關閉方式,一種是正常關閉,即四次揮手關閉連線 還有一種則是異常關閉,我們通常稱之為連線重置 reset 首先說一下正常關閉時四次揮手的狀態變遷,關閉連線的主動方狀態變遷是fin wait 1 fin wait 2 time wait,而關閉連線的被動...
關閉TCP連線的學問
從tcp協議角度來看,乙個已建立的tcp連線有兩種關閉方式,一種是正常關閉,即四次揮手關閉連線 還有一種則是異常關閉,我們通常稱之為連線重置 reset 首先說一下正常關閉時四次揮手的狀態變遷,關閉連線的主動方狀態變遷是fin wait 1 fin wait 2 time wait,而關閉連線的被動...
關閉TCP連線的學問
從tcp協議角度來看,乙個已建立的tcp連線有兩種關閉方式,一種是正常關閉,即四次揮手關閉連線 還有一種則是異常關閉,我們通常稱之為連線重置 reset 首先說一下正常關閉時四次揮手的狀態變遷,關閉連線的主動方狀態變遷是fin wait 1 fin wait 2 time wait,而關閉連線的被動...