【问题标题】:Apache Mina, How to detect when you're sending messages using an invalid socket to the client side?Apache Mina,如何检测何时使用无效套接字向客户端发送消息?
【发布时间】:2017-01-23 19:53:04
【问题描述】:

我有一个使用 MINA 版本 2 的服务器设置。 我对套接字和 tcp 没有太多经验。

问题是如果我与我的服务器建立连接,然后拔下我的互联网并关闭连接,(服务器没有收到连接被关闭的通知)服务器将永远认为我的连接仍然处于活动状态并且有效。

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

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

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

 IoSession.isConnected() IoSession.isActive IoSession.isClosing

它们总是返回真、真、假。此外,在调试模式下,没有说明连接丢失的有用信息。它只是记录了常规的“已发送消息”内容,就好像没有任何问题一样。

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

如果真的无法检测到死连接,我总是可以设置一个连接保持活动例程,其中客户端不断向服务器发送“我在这里”消息,服务器关闭没有连接的会话传入消息持续几秒钟。


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

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

很遗憾

IOException 'Connection reset by peer' 当我写信时不会发生 MINA 中的 IoSession。


编辑:

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


编辑:

但显然,我的计算机应该向服务器发送 RST?根据这个答案。 https://stackoverflow.com/a/1434592/4425643 但这似乎是一种糟糕的端口扫描方式。这是端口扫描的工作原理吗?端口扫描器将数据发送到端口,而受害者的服务以 RST 响应?抱歉,我想我需要一个新问题来解决所有这些问题。但奇怪的是,MINA 在发送数据时不会引发对等方的连接重置。那么我的电脑没有发送 RST。

【问题讨论】:

  • 人们似乎同意在这个线程中 TCP ACK 没有暴露给 Java。如果是这种情况,那么我想在 Java 中设置 ACK 超时是不可能的。stackoverflow.com/questions/2173153/…
  • 服务器在尝试从客户端读取时应该遇到读取超时,或者IOException: connection reset 尝试写入客户端。假设您正在使用读取超时,或者非阻塞或异步等效项,并假设 Mina 没有屏蔽您的 IOException,这是不应该做的。您无法控制 Java 中的 ACK 超时,也没有任何理由认为它们在您的系统中具有异常值。
  • "或任何理由认为它们在您的系统中有异常值" 等待 ack 的发送使连接保持活动状态超过 15 分钟。嗯,我想这很好。也许有一天我会发明无限连接,其中套接字在关闭时保存在客户端,然后在启动时恢复,以便可以重用 MINA 中的连接;)

标签: java sockets tcp mina


【解决方案1】:

TCP 框架没有暴露给 Java。并且 Java 不提供编辑存在于操作系统级别的 TCP 配置的方法。

这意味着我们无法在 Java 中有效地使用 TCP 保持活动,因为我们无法更改其默认配置值。此外,我们无法为发送的消息设置不接收 ACK 的超时。 (了解 TCP 会发现发送的每条消息都将等待来自对等方的 ACK(确认)消息已成功传递。)

Java 只能在以下情况引发异常在任何可能的时间段后超时。

要可靠地跟踪连接状态,您必须按照@Dog 在他的回答中建议的那样实现自己的 Ping/Pong、Keep Alive 或 Heartbeat 系统。 (服务器必须轮询客户端以查看它是否仍然存在,或者客户端必须不断让服务器知道它仍然存在。)

例如,将您的客户端配置为每 10 秒发送一个小数据包。 在 MINA 中,您可以设置会话读取器空闲超时,当会话读取器空闲一段时间时,它将发送一个事件。您可以在传递此事件时终止该连接。将读取器超时设置为比小数据包间隔长一点将导致客户端和服务器之间的随机高延迟。例如,在这种情况下,15 秒的读取器空闲超时将是宽松的。

如果您的服务器很少遇到会话空闲,并且您认为可以通过在会话空闲时轮询客户端来节省带宽,请考虑使用 Apache MINA 保持活动过滤器。

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

【解决方案2】:

您需要的是 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 参数,或者实现自己的功能。

【讨论】:

  • 我做了一个粗略的估计,使用心跳会每月花费我大约 200GB 的额外带宽。我相信这是一种数据浪费,只需使用适当的 TCP ACK 超时就可以避免。如果我能找到如何设置超时。
  • 实际上有 TCP Keep Alive 可以通过 OS 内核修改以设置间隔和设置,根据这个 SO 答案:stackoverflow.com/a/33927447/4425643 你可以在 Java 中使用它,但不幸的是编辑它的值是Java 不可用,并且可能不应该,因为您会修改系统级别的值。对在同一操作系统上运行的其他程序不公平。
【解决方案3】:

socketconnection 在 Internet 协议中的概念是一种错觉。它是操作系统和 TCP 栈提供给你的一种方便的抽象,但实际上都是假的。

在幕后,互联网上的一切都采用单独的数据包的形式。

从计算机向另一台计算机发送数据包的角度来看,没有内置方法可以知道该计算机是否实际接收数据包,除非该计算机(或介于两者之间的其他计算机,如路由器)告诉您数据包是否已收到。

从期望从另一台计算机接收数据包的计算机的角度来看,没有办法提前知道是否有任何数据包到来,是否会或者以什么顺序来 - 直到它们真的到了。一旦它们到达,您收到一个数据包这一事实并不意味着您将来会收到更多数据。

这就是为什么我说连接或套接字是一种错觉。操作系统确定连接是否“活动”的方式只是等待任意时间。在那段时间之后 - 称为 超时 - 如果 TCP 连接的一侧没有收到另一侧的回复,它将假设另一端已断开连接,并且任意将连接状态设置为“关闭”、“死”或“终止”(“超时”)。

所以:

  • 您的服务器不知道您已拔掉 Internet 连接的插头。它无法知道这一点。
  • 您的服务器的 TCP 堆栈已以某种方式配置,如果没有收到响应,则在另一端“放弃”之前等待任意时间。如果此超时设置为非常长的时间段,您可能会觉得您的服务器挂在不再有效的连接上。如果这让您感到困扰,您应该寻找减少超时间隔的方法。

类比:如果您正在与某人通话,并且他们很可能会受伤或被杀,而您正在与他们通话并让他们接听电话,然后电话突然死机... ..好吧,你等多久?你在什么时候假设另一个人已经受伤或被杀?如果您等待几毫秒,在大多数情况下,“超时”太了,因为其他人可能只是在倾听并思考如何响应。如果再等50年,那个人可能早就死了。所以你必须设置一个有意义的合理超时值。

【讨论】:

  • 由于我没有收到“对等方重置连接”异常,因此 TCP ACK 的超时可能是一个非常大的值。感谢您的见解,我将调查 MINA 设置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-25
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-14
相关资源
最近更新 更多