Java 使用 TCP KeepAlive 检测套接字断开连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19786394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detecting Socket Disconnect Using TCP KeepAlive
提问by PeteMitchell
I'm developing a server that hosts 3rd party devices over TCP/IP and have been experiencing sudden connection drops (the devices are connecting via cellular). I need to find a way to detect a disconnect without having to write data to the device itself.
我正在开发一个通过 TCP/IP 托管第 3 方设备的服务器,并且遇到了突然的连接中断(设备通过蜂窝网络连接)。我需要找到一种方法来检测断开连接,而不必将数据写入设备本身。
I've looked at using the TCP keepalive functionality but Java doesn't appear to allow any adjustment of the timing of the keepalive operations.
我已经研究过使用 TCP keepalive 功能,但 Java 似乎不允许对 keepalive 操作的时间进行任何调整。
Is there any suggested method for doing this?
是否有任何建议的方法来执行此操作?
My simplified socket code is as follows:
我的简化套接字代码如下:
public class Test2Socket {
public static void main(String[] args) {
try {
ServerSocket skt = new ServerSocket(1111);
Socket clientSocket = skt.accept();
clientSocket.setKeepAlive(true);
System.out.println("Connected..");
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while((inputLine = input.readLine()) != null)
{
System.out.println(inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Any feedback would be greatly appreciated.
任何反馈将不胜感激。
采纳答案by Laszlo Valko
You will not get far with the built-in keep-alives of the TCP stack. That's because the keep-alive interval cannot be tuned by your application, it is set by the OS, and the defaults are rather high (hours). This is not specific to Java.
使用 TCP 堆栈的内置 keep-alive,您不会走得太远。这是因为您的应用程序无法调整保持活动间隔,它是由操作系统设置的,并且默认值相当高(小时)。这不是 Java 特有的。
If you need to time out in a reasonable time, you have to implement some kind of keep alive in the protocol to be used. Most of the high-level protocols I have seen have some kind of NOP functionality, where you send an "Are you there?" message and the other party sends a "Yes, I'm here" reply without doing anything else.
如果您需要在合理的时间内超时,则必须在要使用的协议中实现某种保活。我见过的大多数高级协议都具有某种 NOP 功能,您可以在其中发送“您在那里吗?” 消息,另一方发送“是的,我在这里”的回复而不做任何其他事情。
回答by user207421
Set a read timeout, with setSoTimeout(),
to a reasonable value, say double the expected response time, and catch the resulting SocketTimeoutException.
将读取超时设置setSoTimeout(),
为一个合理的值,比如预期响应时间的两倍,并捕获结果SocketTimeoutException.
NB there is no such thing as "Java TCP KeepAlive".
注意,没有“Java TCP KeepAlive”这样的东西。
回答by Andreas Florath
When you call setKeepalive() on a socket the system parameters (which are tunable) are used. (Checked it under Debian 8 with openjdk7.)
当您在套接字上调用 setKeepalive() 时,将使用系统参数(可调)。(在 Debian 8 下使用 openjdk7 进行了检查。)
Because I needed exactly the same functionality, I wrote a small library called libdontdiethat can be preloaded and works with Java.
因为我需要完全相同的功能,所以我编写了一个名为libdontdie的小库,它可以预加载并与 Java 一起使用。
回答by Cory Klein
For an in-depth discussion of TCP Keep-Alives see my answer here.
对于TCP的深入讨论保持活动见我的答案在这里。
But basically TCP Keep-Alives are likely the best method for detecting a stale connection. The main problem is that OS defaults are set at 2 hours before the connection is checked with 11 more minutes of Keep-Alive packets before the connection will actually be dropped.
但基本上 TCP Keep-Alives 可能是检测陈旧连接的最佳方法。主要问题是操作系统默认设置为 2 小时,然后再检查连接 11 分钟的 Keep-Alive 数据包,然后才会实际断开连接。
Don't write your own application-layer Keep Alive protocol when TCP already has it built in. All you have to do is set the TCP time outto something more reasonable like 2-3 minutes.
当 TCP 已经内置了它时,不要编写自己的应用层 Keep Alive 协议。您所要做的就是将 TCP 超时设置为更合理的时间,例如 2-3 分钟。
Unfortunately, since TCP timeouts are managed at the OS level and not from within the JVM, it is difficult (but not impossible) to configure TCP timeouts from within your code on a per-socket basis.
不幸的是,由于 TCP 超时是在操作系统级别而不是在 JVM 内部管理的,因此很难(但并非不可能)在您的代码中基于每个套接字配置 TCP 超时。
回答by m5c
author of thislibrary here :-)
这个库的作者在这里:-)
As has been stated before, unless you rely on difficult-to-configure functionality implemented directly in the TCP protocol (keep-alives), you can hardly detect breakdowns without actually sending data over a connection.
如前所述,除非您依赖直接在 TCP 协议中实现的难以配置的功能(keep-alives),否则如果不通过连接实际发送数据,您就很难检测到故障。
The referenced library encapsulates traditional Java Sockets, while adding easily configurable periodic connectivity checks and ACKing. (Those will stay invisible to the application programmer). As soon as a breakdown is detected, all inscribed observers will be notified. (Depending on you configuration that can be close to real-time).
引用的库封装了传统的 Java 套接字,同时添加了易于配置的定期连接检查和 ACK。(那些对应用程序员来说是不可见的)。一旦检测到故障,将通知所有登记的观察员。(取决于您的配置,可以接近实时)。
The upside is that the lib is rather easy to use (and at least in my own projects works quite reliable).
好处是 lib 相当容易使用(至少在我自己的项目中工作非常可靠)。
The downside is, the application layer is not meant to be used for connectivity checks. So basically that lib is using things in a way they are probably not meant to.
缺点是,应用层不打算用于连接检查。所以基本上,lib 正在以一种他们可能不打算使用的方式使用东西。
Side note: You mentioned your clients are cellulars. While the linked library willwork on android, you might have a look at Push Notification Servicesinstead of dealing with connectivity issues yourself. That could improve e.g. battery consumption.
旁注:你提到你的客户是蜂窝。虽然链接库可以在 android 上运行,但您可能需要查看推送通知服务,而不是自己处理连接问题。这可以改善例如电池消耗。