Apache Mina,如何检测何时使用无效套接字向客户端发送消息?

时间:2016-09-15 17:27:51

标签: java sockets tcp mina

我使用MINA版本2进行了服务器设置。 我对socket和tcp没有多少经验。

问题是如果我连接到我的服务器,然后拔掉我的互联网并关闭连接,(服务器没有得到关闭连接的通知),服务器将永远认为我的连接仍然是活动的,有效的。

服务器将继续向我的连接发送消息,即使我的计算机上没有绑定到本地端口的任何内容,也不会抛出任何异常。

如何测试连接是否仍然存在?

我尝试在调试模式下运行MINA日志记录,并记录

 IoSession.isConnected() IoSession.isActive IoSession.isClosing

他们总是回归真实,真实,虚假。此外,在调试模式下,没有有用的信息表明连接已丢失。它只是记录了常规的“发送消息”内容,好像没有任何错误。

从使用Flash动作脚本开始,我遇到过Flash会在无效套接字上运行的错误。这让我相信它说服务器上的套接字不再对连接有效。换句话说,如果flash可以检测到无效的套接字,那么Java服务器应该能够检测到它是否正确?

如果真的没有办法检测死连接,我总是可以建立一个连接保持活动例程,客户端不断向服务器发送“我在这里”消息,服务器关闭没有连接的会话传入的消息持续一段时间。

编辑:在得知“套接字”是私有的并且从未通过网络共享后,我设法找到了更好的结果,我找到了这个SO线程。

Java socket API: How to tell if a connection has been closed?

不幸的是

  

IOException'通过peer重置连接'当我写入时不会发生   MINA的IoSession。

编辑:

在Java中是否有任何方法可以检测在发送数据包后何时未收到对TCP数据包的ACK? ACK超时?

编辑:

然而,显然,我的电脑应该向服务器发送RST?根据这个答案。 https://stackoverflow.com/a/1434592/4425643 但这似乎是一种糟糕的端口扫描方式。这是端口扫描的工作原理吗?端口扫描程序将数据发送到端口,受害者的服务是否使用RST响应?对不起,我想我需要一个新问题。但奇怪的是MINA在发送数据时不会通过对等体重置连接。那么我的电脑发送RST。

3 个答案:

答案 0 :(得分:4)

Internet协议中 socket connection 的概念是一种幻觉。它是操作系统和TCP堆栈提供给您的一种方便的抽象,但实际上,它都是假的。

在幕后,互联网上的所有内容都采用个人数据包的形式

从计算机向另一台计算机发送数据包的角度来看,没有内置的方法来了解该计算机是否实际接收数据包,除非该计算机(或其他计算机,如路由器)告诉您收到的数据包是否收到。

从希望从另一台计算机接收数据包的计算机的角度来看,没有办法事先知道是否有任何数据包即将到来,来或以什么顺序 - 直到他们实际到达。一旦他们到达,只是你收到一个包的事实并不意味着你将来会再收到。

这就是为什么我说连接或插座是一种错觉。操作系统确定连接是否为“活着”的方式。或者不是,只需等待任意数量的时间。经过这段时间后 - 称为超时 - 如果TCP连接的一端没有从另一侧收到回复,则只会假设另一端已断开连接,并且任意地将连接状态设置为"关闭","死"或者"终止" ("超时")。

所以:

  • 您的服务器无线索您已拔下Internet连接上的插头。它无从得知这一点。
  • 您的服务器的TCP堆栈已经配置了某种方式,等待任意时间,然后放弃"如果没有收到回复,则在另一端。如果将此超时设置为非常长的时间段,则可能会显示您的服务器正在挂起不再有效的连接。如果这困扰你,你应该研究减少超时间隔的方法。
类比:如果您正在与某人打电话,那么他们很可能会受伤或被杀,而且您正在与他们交谈并让他们接听,然后电话突然死亡.....嗯,你等多久了?在什么时候你认为对方受伤或被杀?如果你等待几毫秒,在大多数情况下,"超时",因为另一个人可能正在倾听并思考如何回应。如果你等了50年,这个人可能会在那个时候长期死亡。所以你必须设置一个有意义的合理的超时值。

答案 1 :(得分:3)

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

根据@ allquicatic的回答,在TCP中没有完全可靠的内置方法。你必须实现一种方法来明确询问客户“你还在吗?”并在指定的时间内等待答案。

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

  

keepalive(KA)是一个设备发送给另一个设备的消息,用于检查两者之间的链接是否正在运行,或者是为了防止此链接被破坏。

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

  

在计算机科学中,心跳是由硬件或软件生成的周期性信号,用于指示正​​常操作或同步系统的其他部分。[1]通常,机器之间定期发送心跳,大小为秒。如果一段时间内没有收到心跳 - 通常是几次心跳间隔 - 应该发送心跳的机器被认为已经失败。[2]

实现一个的最简单方法是定期发送任意数据 - 例如一个null命令。如果在指定的超时时间内未收到ACK,则正确编程的TCP堆栈将超时,然后您将获得IOException 'Connection reset by peer'

如果您想要比默认超时更精细的控制,您可能必须手动调整TCP参数,或实现自己的功能。

答案 2 :(得分:1)

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