簡體   English   中英

如何防止 .NET 庫在關閉時發送 RST 數據包

[英]How to prevent .NET libraries from sending RST packet on close

我正在做一些測試,試圖在庫 (.NET) 中隔離一些奇怪的行為。 當我通過 C++ 使用 Winsock API 並簡單地調用closesocket() ,我看到 Windows 端發送 FIN/ACK 數據包,而遠程端發送回一個 ACK​​ 數據包。 這就是我所說的優雅關閉。 但是,在用 C# 編程時,我沒有看到我所說的優雅關閉。

在 C# 中,我打開我的套接字,然后在關閉它時,我看到 Windows在第一次調用Socket.Shutdown()時發送一個 FIN 數據包。 但是,無論如何,當我在 C# 中調用Socket.Close()時,會發送一個 RST 數據包並立即斷開連接。 這讓我感到困惑,因為根據我在網上閱讀的內容,TCP 關閉過程應該是 FIN/ACK -> ACK(實際上來自雙方,但現在,我只關心“我的”方面); 即混合中根本不應該有 RST 數據包。 從我讀過的內容來看,顯然,只有在接收方不確定連接狀態並想要退出時才會發送 RST 數據包。

為什么這個 RST 數據包是在 .NET 中計划關閉時發送的,而不是在 winsock API 中計划關閉時發送? 有沒有辦法在從 .NET 正常關閉期間阻止 RST 數據包的傳輸?

如果這很重要,在兩個代碼路徑中,我都會在調用相應的close()方法之前讀取套接字上的所有可用數據。

閱讀Socket.Close的 .NET 文檔,這是我發現的:

對於面向連接的協議,建議在調用 Close 方法之前先調用 Shutdown。 這確保所有數據在連接的套接字關閉之前在其上發送和接收。 如果您需要在不先調用 Shutdown 的情況下調用 Close,則可以通過將 DontLinger Socket 選項設置為 false 並指定非零超時間隔來確保將發送排隊等待傳出傳輸的數據。 然后關閉將阻塞,直到發送此數據或直到指定的超時到期。 如果將 DontLinger 設置為 false 並指定零超時間隔,則 Close 會釋放連接並自動丟棄傳出的排隊數據。

這實際上是有道理的。 如果緩沖區中仍有數據(操作系統一)並且您斷開連接或終止進程,則連接將被重置(TCP 規范中的更多詳細信息)。

至於何時發送 RST,請查看TCP 指南

我的猜測是仍有一些未設置或傳輸中的數據或在觸發 RST 的傳出/傳入緩沖區中。

以下代碼可能會阻止 RST 數據包。 這是因為發送 FIN 數據包后要等待 60 秒。

socket.Close(60);

關閉方法說明在這里

在類似的情況下,我調用了socket.Disconnect(false)而不是socket.Close()

if (theSenderSocket != null){
    theSenderSocket.Disconnect(false);
   }

然后檢查 Wireshark 過濾器發現,如果是 RST/ACK,它正在發送 FIN/ACK。

就在最近遇到了一個類似的問題,即應用程序與 Exchange Server 對話 POP3。 當 .NET 程序完成時,它不正常地關閉,Exchange 將 POP3 對話視為“中止”並將其回滾。

原因是我認為 TCP RST 是一種“單向”消息——您不必等待回復。 所以這就是 .NET 發送的(或者可能是它終止后的任何程序。)一種可能的解決方案是在關閉套接字后和退出程序之前等待一段時間:

Thread.Sleep(5000);

這對我之前提到的 POP3 問題有效; 等待時間導致連接正常關閉,Exchange 不再中止會話。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM