簡體   English   中英

Apache Mina,如何檢測何時使用無效套接字向客戶端發送消息?

[英]Apache Mina, How to detect when you're sending messages using an invalid socket to the client side?

我有一個使用MINA版本2的服務器設置。我對套接字和tcp沒有太多經驗。

問題是如果我連接到我的服務器,然后拔掉我的互聯網並關閉連接,(服務器沒有得到關閉連接的通知)服務器將永遠認為我的連接仍然是活動和有效的。

服務器將繼續向我的連接發送消息,並且即使我的計算機上沒有綁定到本地端口的任何內容也不會拋出任何異常。

如何測試連接是否仍然存在?

我已經嘗試在調試模式下運行MINA日志記錄並記錄

 IoSession.isConnected() IoSession.isActive IoSession.isClosing

他們總是回歸真實,真實,虛假。 此外,在調試模式下,沒有有用的信息表明連接已丟失。 它只記錄了常規的“發送消息”內容,好像沒有任何錯誤。

從使用Flash動作腳本開始,我遇到過閃存會在無效套接字上運行的錯誤。 這讓我相信它說服務器上的套接字不再對連接有效。 換句話說,如果flash可以檢測到無效的套接字,那么Java服務器應該能夠檢測到它是否正確?

如果真的沒有辦法檢測死連接,我總是可以建立一個連接保持活動例程,客戶端不斷向服務器發送“我在這里”消息,服務器關閉沒有傳入消息的會話一段時間。


編輯:在得知“套接字”是私有的並且從未通過網絡共享后,我設法為我的問題找到了更好的結果,我找到了這個SO線程。

Java套接字API:如何判斷連接是否已關閉?

不幸

IOException'由peer重置連接'當我寫入MINA中的IoSession時不會發生。


編輯:

在Java中是否有任何方法可以檢測在發送數據包后何時未收到對TCP數據包的ACK? ACK超時?


編輯:

但顯然,我的電腦應該向服務器發送一個RST? 根據這個答案。 https://stackoverflow.com/a/1434592/4425643但這似乎是一種糟糕的端口掃描方式。 這是端口掃描的工作原理嗎? 端口掃描程序將數據發送到端口,受害者的服務是否使用RST響應? 對不起,我想我需要一個新問題。 但奇怪的是MINA在發送數據時不會通過對等體重置連接。 那么我的電腦發送RST。

Internet協議中的套接字連接的概念是一種幻覺。 它是操作系統和TCP堆棧為您提供的一種方便的抽象,但實際上,它都是假的。

在引擎蓋下,互聯網上的所有內容都采用單個數據包的形式。

從計算機向另一台計算機發送數據包的角度來看,沒有內置的方法來了解該計算機是否實際接收數據包,除非該計算機(或其間的某些其他計算機,如路由器)告訴您數據包曾經或者沒有收到過。

從希望從另一個計算機接收數據包的計算機的角度來看,有沒有辦法事先知道的任何數據包是否有未來, 永遠不會來了,還是以什么順序-直到他們實際到帳 一旦他們到達,只是你收到一個包的事實並不意味着你將來會再收到。

這就是我說連接或插座是幻覺的原因。 操作系統確定連接是否“活動”的方式只是等待任意數量的時間。 經過那段時間 - 稱為超時 - 如果TCP連接的一端沒有從另一側聽到回來,它只會假設另一端已經斷開,並且任意將連接狀態設置為“關閉” “,”死“或”終止“(”超時“)。

所以:

  • 您的服務器不知道您已拔掉Internet連接上的插頭。 它無從得知。
  • 您的服務器的TCP堆棧已經配置了某種方式,如果沒有收到響應,則在另一端“放棄”之前等待任意時間。 如果將此超時設置為非常長的時間段,則可能會顯示您的服務器正在掛起不再有效的連接。 如果這困擾你,你應該研究減少超時間隔的方法。

打個比方:如果你正和某人打電話,他們有很大的風險讓他們受傷或被殺,而你正在與他們交談並讓他們回答,然后手機突然死了.....你等多久了? 在什么時候你認為對方受傷或被殺? 如果你等待幾毫秒,在大多數情況下,它太短暫的“超時”,因為另一個人可能正在傾聽並思考如何回應。 如果你等了50年,這個人可能會在那個時候長期死亡。 所以你必須設置合理的超時值才有意義。

你想要的是KeepAlive,心跳或ping。

根據@ allquicatic的回答,在TCP中沒有完全可靠的內置方法。 你必須實現一種方法來明確詢問客戶“你還在嗎?” 並在指定的時間內等待答案。

https://en.wikipedia.org/wiki/Keepalive

keepalive(KA)是一個設備發送給另一個設備的消息,用於檢查兩者之間的鏈接是否正在運行,或者是為了防止此鏈接被破壞。

https://en.wikipedia.org/wiki/Heartbeat_(computing)

在計算機科學中,心跳是由硬件或軟件生成的周期性信號,用於指示正​​常操作或同步系統的其他部分。[1] 通常,機器之間定期發送心跳,大小為秒。 如果一段時間內沒有收到心跳 - 通常是幾次心跳間隔 - 應該發送心跳的機器被認為是失敗的。[2]

實現一個的最簡單方法是定期發送任意數據 - 例如空命令。 如果在指定的超時時間內未收到ACK,則正確編程的TCP堆棧將超時,然后您將獲得IOException 'Connection reset by peer'

如果您想要比默認超時更精細的控制,則可能必須手動調整TCP參數,或實現自己的功能。

TCP框架不會暴露給Java。 並且Java沒有提供編輯OS級別上存在的TCP配置的方法。

這意味着我們不能有效地在Java中使用TCP keep alive,因為我們無法更改其默認配置值。 此外,我們無法設置未收到發送消息的ACK的超時。 (了解TCP以發現發送的每條消息都將等待來自對等方的ACK(確認)消息已成功傳遞。)

Java只能針對以下情況拋出異常,例如在自定義時間內未完成TCP握手的超時,從對等方收到RST時的“由對等方連接重置”異常,以及在任何情況下發生ACK超時的異常可能的一段時間。

要可靠地跟蹤連接狀態,您必須在答案中建議使用@Dog建議的Ping / Pong,Keep Alive或Heartbeat系統。 (服務器必須輪詢客戶端以查看它是否仍然存在,或者客戶端必須連續讓服務器知道它仍在那里。)

例如,將客戶端配置為每10秒發送一個小數據包。 在MINA中,您可以設置會話讀取器空閑超時,該超時將在會話讀取器空閑一段時間后發送事件。 您可以在交付此活動時終止該連接。 將讀取器超時設置為比小數據包間隔稍長,將考慮客戶端和服務器之間的隨機高延遲。 例如,在這種情況下,讀取器空閑超時15秒將是寬松的。

如果您的服務器很少會遇到會話空閑,並且您認為可以通過在會話空閑時輪詢客戶端來節省帶寬,請查看使用Apache MINA Keep Alive Filter。

https://mina.apache.org/mina-project/apidocs/org/apache/mina/filter/keepalive/KeepAliveFilter.html

暫無
暫無

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

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