繁体   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