【问题标题】:Detecting Socket Disconnect Using TCP KeepAlive使用 TCP KeepAlive 检测套接字断开连接
【发布时间】:2013-11-16 04:10:17
【问题描述】:

我正在开发一个服务器,该服务器通过 TCP/IP 托管第 3 方设备,并且遇到了突然的连接中断(设备通过蜂窝网络连接)。我需要找到一种方法来检测断开连接,而无需将数据写入设备本身。

我已经研究过如何使用 TCP keepalive 功能,但 Java 似乎不允许对 keepalive 操作的时间进行任何调整。

有什么建议的方法吗?

我的简化套接字代码如下:

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();
        }
    }
}

任何反馈都将不胜感激。

【问题讨论】:

  • 为什么不能向客户端写入数据? keepalive 间隔通常固定为 2 小时,因此无法快速检测掉线。
  • 我试过这样做。该设备只是向我抛出了一个错误,并且有点嘶嘶作响。
  • 看看我的案例和解决方案stackoverflow.com/a/31741436/413032
  • 壮观的是,错误的答案是最受投票和接受的解决方案。对我来说很明显,检测 Socket 超时/网络断开是 TCP 存在的主要原因。这方面不应该在应用程序级别处理,它应该发送 NOP。 TCP 已经发送了 SYN/ACK 数据包。

标签: java multithreading sockets tcp ip


【解决方案1】:

TCP 堆栈的内置保持活动不会让您走得太远。这是因为您的应用程序无法调整保活间隔,它是由操作系统设置的,并且默认值相当高(小时)。这不是 Java 特有的。

如果您需要在合理的时间内超时,则必须在要使用的协议中实现某种保持活动状态。我见过的大多数高级协议都具有某种 NOP 功能,您可以在其中发送“你在吗?”消息,对方发送“是的,我在这里”回复,没有做任何其他事情。

【讨论】:

  • 您问题的第一部分根本不正确。当然也有设置定时器的系统调用:setsockopt(... TCP_KEEPIDLE ...)。
  • 第二部分的提议很危险,并且增加了客户端和服务器的复杂性:您在这里混淆了 4 级和 7 级(并且必须手动整理所有内容)。 TCP 给了你你想要的东西——你为什么还要这样做?有技术解决方案 - 甚至适用于 Java。
  • @AndreasFlorath:我认为原始发帖人真的很想看到:a) 一个关于 Windows、Mac OS X 等系统调用的文档的链接; b) 如何以可移植的方式从 Java 中使用这些。
  • @AndreasFlorath 用于设置每个套接字保持活动计时器的套接字选项并不存在于所有平台上,Java 中也不存在。
  • @LaszloValko:这是在 Windows 上调用的链接:msdn.microsoft.com/en-us/library/windows/desktop/…
【解决方案2】:

有关 TCP Keep-Alives 的深入讨论,请参阅我的回答 here

但基本上 TCP Keep-Alives 可能是检测陈旧连接的最佳方法。主要问题是操作系统默认设置为在连接被检查前 2 小时,并在连接实际断开之前再过 11 分钟的 Keep-Alive 数据包。

当 TCP 已经内置时,不要编写您自己的应用层 Keep Alive 协议。您所要做的就是 set the TCP time out 到更合理的时间,例如 2-3 分钟。

不幸的是,由于 TCP 超时是在操作系统级别而不是在 JVM 中管理的,因此很难(但并非不可能)在代码中基于每个套接字配置 TCP 超时。

【讨论】:

    【解决方案3】:

    当您在套接字上调用 setKeepalive() 时,将使用系统参数(可调)。 (用openjdk7在Debian 8下检查过。)

    因为我需要完全相同的功能,所以我编写了一个名为 libdontdie 的小型库,它可以预加载并与 Java 一起使用。

    【讨论】:

      【解决方案4】:

      设置读取超时,将setSoTimeout(), 设置为合理值,例如将预期响应时间加倍,并捕获结果SocketTimeoutException.

      注意,没有“Java TCP KeepAlive”之类的东西。

      【讨论】:

        【解决方案5】:

        this 库的作者 这里:-)

        如前所述,除非您依赖直接在 TCP 协议中实现的难以配置的功能(保持活动状态),否则如果不通过连接实际发送数据,您几乎无法检测到故障。

        引用的库封装了传统的 Java 套接字,同时添加了易于配置的定期连接检查和 ACK。 (这些对应用程序程序员来说是不可见的)。 一旦检测到故障,将通知所有登记的观察者。 (取决于您的配置,可以接近实时)。

        好处是这个库相当容易使用(至少在我自己的项目中工作相当可靠)。

        不利的一面是,应用层并不打算用于连接检查。所以基本上那个 lib 正在以他们可能不打算的方式使用东西。

        旁注: 你提到你的客户是蜂窝网络。虽然链接库在 android 上运行,但您可以查看 Push Notification Services 而不是自己处理连接问题。这可以改善例如电池消耗。

        【讨论】:

          猜你喜欢
          • 2020-07-04
          • 2011-09-18
          • 2020-11-30
          • 2012-12-10
          • 1970-01-01
          • 2013-11-22
          • 1970-01-01
          • 2011-11-27
          相关资源
          最近更新 更多