我使用MINA版本2进行了服务器设置。 我对socket和tcp没有多少经验。
问题是如果我连接到我的服务器,然后拔掉我的互联网并关闭连接,(服务器没有得到关闭连接的通知),服务器将永远认为我的连接仍然是活动的,有效的。
服务器将继续向我的连接发送消息,即使我的计算机上没有绑定到本地端口的任何内容,也不会抛出任何异常。
如何测试连接是否仍然存在?
我尝试在调试模式下运行MINA日志记录,并记录
IoSession.isConnected() IoSession.isActive IoSession.isClosing
他们总是回归真实,真实,虚假。此外,在调试模式下,没有有用的信息表明连接已丢失。它只是记录了常规的“发送消息”内容,好像没有任何错误。
从使用Flash动作脚本开始,我遇到过Flash会在无效套接字上运行的错误。这让我相信它说服务器上的套接字不再对连接有效。换句话说,如果flash可以检测到无效的套接字,那么Java服务器应该能够检测到它是否正确?
如果真的没有办法检测死连接,我总是可以建立一个连接保持活动例程,客户端不断向服务器发送“我在这里”消息,服务器关闭没有连接的会话传入的消息持续一段时间。
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。
答案 0 :(得分:4)
Internet协议中 socket 或 connection 的概念是一种幻觉。它是操作系统和TCP堆栈提供给您的一种方便的抽象,但实际上,它都是假的。
在幕后,互联网上的所有内容都采用个人数据包的形式。
从计算机向另一台计算机发送数据包的角度来看,没有内置的方法来了解该计算机是否实际接收数据包,除非该计算机(或其他计算机,如路由器)告诉您收到的数据包是否收到。
从希望从另一台计算机接收数据包的计算机的角度来看,没有办法事先知道是否有任何数据包即将到来,曾来或以什么顺序 - 直到他们实际到达。一旦他们到达,只是你收到一个包的事实并不意味着你将来会再收到。
这就是为什么我说连接或插座是一种错觉。操作系统确定连接是否为“活着”的方式。或者不是,只需等待任意数量的时间。经过这段时间后 - 称为超时 - 如果TCP连接的一端没有从另一侧收到回复,则只会假设另一端已断开连接,并且任意地将连接状态设置为"关闭","死"或者"终止" ("超时")。
所以:
答案 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