TCP中異常關閉鏈接的意義 異常關閉的情況


終止一個連接的正常方式是發送FIN。 在發送緩沖區中 所有排隊數據都已發送之后才發送FIN,正常情況下沒有任何數據丟失。

但我們有時也有可能發送一個RST報文段而不是F IN來中途關閉一個連接。這稱為異常關閉 。 

進程關閉socket的默認方式是正常關閉,如果需要異常關閉,利用 SO_LINGER選項來控制。

異常關閉一個連接對應用程序來說有兩個優點:

(1)丟棄任何待發的已經無意義的 數據,並立即發送RST報文段;

(2)RST的接收方利用關閉方式來 區分另一端執行的是異常關閉還是正常關閉。

值得注意的是RST報文段不會導致另一端產生任何響應,另一端根本不進行確認。收到RST的一方將終止該連接。程序行為如下:

阻塞模型下,內核無法主動通知應用層出錯,只有應用層主動調用read()或者write()這樣的IO系統調用時,內核才會利用出錯來通知應用層對端RST。

非阻塞模型下,select或者epoll會返回sockfd可讀,應用層對其進行讀取時,read()會報錯RST。 

游戲測試過程中發現某些socket錯誤經常出現,以下是測試游戲服務器時通常考慮的case. 
服務器端: 
1. 
Case:客戶端程序正常運行的情況下,拔掉網線,殺掉客戶端程序 
目的:模擬客戶端死機、系統突然重啟、網線松動或網絡不通等情況 
結論:這種情況下服務器程序沒有檢測到任何異常,並最后等待“超時”才斷開TCP連接

2. 
Case:客戶端程序發送很多數據包后正常關閉Socket並exit進程(或不退出進程) 
目的:模擬客戶端發送完消息后正常退出的情況 
結論:這種情況下服務器程序能夠成功接收完所有消息,並最后收到“對端關閉”(Recv返回零)消息

3. 
Case:客戶端程序發送很多數據包后不關閉Socket直接exit進程 
目的:模擬客戶端程序退出而忘記關閉Socket的情況(比如通過Windows窗口的關閉圖標退出進程,而沒有捕獲相應關閉事件做正常退出處理等) 
結論:這種情況下服務器程序能夠收到部分TCP消息,然后收到“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)錯誤

4. 
Case:客戶端程序發送很多數據包的過程中直接Kill進程 
目的:模擬客戶端程序崩潰或非正常方式結束進程(比如Linux下”kill -9″或Windows的任務管理器殺死進程)的情況 
結論:這種情況下服務器程序很快收到“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)錯誤

5. 
Case:客戶端程序發送很多數據包后正常關閉Socket並exit進程(或不退出進程) 
目的:模擬客戶端正常關閉Socket后,服務器端在檢查到TCP對端關閉前向客戶端發送消息的情況 
結論:這種情況下服務器程序接收和發送部分TCP消息后,在Send消息時產生“32: Broken pipe”(Linux下)或“10053: An established connection was aborted by the software in your host machine”(Windows下)錯誤

總結: 
當TCP連接的進程在忘記關閉Socket而退出、程序崩潰、或非正常方式結束進程的情況下(Windows客戶端),會導致TCP連接的對端進程產生“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)錯誤

當TCP連接的進程機器發生死機、系統突然重啟、網線松動或網絡不通等情況下,連接的對端進程可能檢測不到任何異常,並最后等待“超時”才斷開TCP連接

當TCP連接的進程正常關閉Socket時,對端進程在檢查到TCP關閉事件之前仍然向TCP發送消息,則在Send消息時會產生“32: Broken pipe”(Linux下)或“10053: An established connection was aborted by the software in your host machine”(Windows下)錯誤

客戶端 
1. 
服務器端已經close了Socket,客戶端再發送數據 
目的:測試在TCP對端進程已經關閉Socket時,本端進程還未檢測到連接關閉的情況下繼續向對端發送消息 
結論:第一包可以發送成功,但第二包發送失敗,錯誤碼為“10053: An established connection was aborted by the software in your host machine”(Windows下)或“32: Broken pipe,同時收到SIGPIPE信號”(Linux下)錯誤

2. 
服務器端發送數據到TCP后close了Socket,客戶端再發送一包數據,然后接收消息 
目的:測試在TCP對端進程發送數據后關閉Socket,本端進程還未檢測到連接關閉的情況下發送一包消息,並接着接收消息 
結論:客戶端能夠成功發送第一包數據(這會導致服務器端發送一個RST包 <已抓包驗證>),客戶端再去Recv時,對於Windows和Linux程序有如下不同的表現: 
Windows客戶端程序:Recv失敗,錯誤碼為“10053: An established connection was aborted by the software in your host machine” 
Linux客戶端程序:能正常接收完所有消息包,最后收到正常的對端關閉消息(這一點與Window下不一樣)

3. 
服務器端在TCP的接收緩沖區中還有未接收數據的情況下close了Socket,客戶端再收包 
目的:測試在TCP的接收緩沖區中還有未接收數據的情況下關閉Socket時,對端進程是否正常 
結論:這種情況服務器端就會向對端發送RST包,而不是正常的FIN包(已經抓包證明),這就會導致客戶端提前(RST包比正常數據包先被收到)收到“10054: An existing connection was forcibly closed by the remote host”(Windows下)或“104: Connection reset by peer”(Linux下)錯誤

總結: 
當TCP連接的對端進程已經關閉了Socket的情況下,本端進程再發送數據時,第一包可以發送成功(但會導致對端發送一個RST包過來): 
之后如果再繼續發送數據會失敗,錯誤碼為“10053: An established connection was aborted by the software in your host machine”(Windows下)或“32: Broken pipe,同時收到SIGPIPE信號”(Linux下)錯誤; 
之后如果接收數據,則Windows下會報10053的錯誤,而Linux下則收到正常關閉消息

TCP連接的本端接收緩沖區中還有未接收數據的情況下close了Socket,則本端TCP會向對端發送RST包,而不是正常的FIN包,這就會導致對端進程提前(RST包比正常數據包先被收到)收到“10054: An existing connection was forcibly closed by the remote host”(Windows下)或“104: Connection reset by peer”(Linux下)錯誤


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM