2010-01-29 84 views

回答

10

TCP不能像這樣工作。即使TCP堆棧知道另一端關閉它,操作系統也不會釋放資源,即文件描述符和端口,直到應用程序明確關閉套接字或死亡。在從對等端收到FIN時,從內核到用戶應用程序沒有回調。操作系統向對方確認,但在發送其FIN數據包之前等待應用程序調用close()。看看TCP state transition diagram - 你在被動關閉框。

檢測這種情況的一種方法是在不爲每個套接字指定線程的情況下使用select/poll/epoll/kqueue函數系列。被動關閉的套接字將被標記爲可讀,讀取嘗試將返回EOF。

希望這會有所幫助。

+0

TCP狀態轉換圖鏈接給出了404 – 2015-06-12 14:11:03

6

雙方都必須從連接中讀取數據,以便他們可以檢測到對方已關閉。當讀取返回-1時,這意味着另一端關閉了連接,這是你關閉結束的線索。

+0

我的代碼是一個多線程代碼,我不能浪費我的一個線程來查看連接並查找它是否關閉。我應該提到,我擁有成千上萬個這樣的連接,而不僅僅是一個。 – Shayan 2010-01-29 22:43:37

+3

然後,您將不得不切換到NIO並執行多路複用IO。如果要檢測來自對等體的優雅關閉,則必須以某種方式從套接字讀取數據。 – nos 2010-01-29 23:15:21

0

你可能想擁有一個連接池。

+0

編號只需自動關閉連接。 – Shayan 2010-01-29 22:50:32

4

如果您仍然從您的套接字讀取數據,那麼您將在關閉時檢測-1。

如果您不再讀取套接字,請繼續並關閉它。

如果它們都不是這些,你可能有一個線程等待一個事件。這不是您想要處理數千個端口的方式! Java會開始在Windows的大約3000個線程中獲取pukey - 在Linux中更少(我不知道爲什麼)。

確保您使用的是NIO。使用單個線程來管理您的所有端口(連接池)。它應該只抓取線程中的數據,並將其轉發到隊列中。在那一點上,我想我會有一個線程池將數據從隊列中取出並處理它,因爲實際處理來自端口的數據需要一些時間。

將線程連接到每個端口將不起作用,並且是需要NIO的最大原因。另外,將某種「關閉」消息作爲觸發關閉端口的流的一部分可能會使事情工作更快 - 但仍然需要處理-1來覆蓋破碎流的情況

+0

這邊不知道它是否完成。另外發送來自另一方的開銷的密切消息太多了。大多數情況下,我們發送兩條消息。 – Shayan 2010-01-29 23:01:37

+2

我不確定你的意思,但你可以簡單地用一個特殊字符或字節碼結束一條消息,以告訴聽衆它是最後一條消息。它幾乎免費。 – 2010-01-29 23:31:42

+1

如果發送一些額外的字節來表示關閉的開銷太大,那麼您要麼有非常特殊的要求,要麼您正在遭受不成熟的優化。 – Confusion 2010-01-30 00:24:30

3

通常的解決方案是讓對方知道你要在關閉連接之前關閉連接。例如,在SMTP協議的情況下,服務器在關閉連接之前將發送'221 Bye'。

+0

儘管這是一個很好的優化,但它不會處理丟失的連接,並最終會堆積開放的端口。在有數千個端口打開的系統中這是不可接受的,但它確實減少了「我可以關閉此端口」掃描的頻率。 – 2010-01-30 01:31:04

相關問題