【问题标题】:Java socket polling for checking if client is available用于检查客户端是否可用的 Java 套接字轮询
【发布时间】:2013-09-07 01:28:49
【问题描述】:

我正在尝试轮询服务器端的套接字以检查客户端是否仍然可用。我在这里检查了几个线程,但似乎没有任何效果。

我发现没有直接的检查方法,所以我尝试对套接字执行写操作,并且... Java 正在写入套接字(当客户端断开连接时)并且我没有遇到预期 IOException 的异常.

我设置了一个线程,它应该每秒执行一次轮询发送数据包。大约一分钟后发送到断开连接的客户端时,我收到“操作超时”的响应。

我也尝试过使用套接字 setSoTimeout,但它也没有按预期工作。

有人对如何使它工作有任何建议吗?

非常感谢您。

最好的问候, 汤姆

【问题讨论】:

  • 在客户端机器上,是否有病毒扫描程序在运行?当我通过尝试连接来检查可达性时遇到了这种情况,病毒扫描程序导致所有连接都正确设置,但它们是“假的”。只是为了确定:我们在谈论 TCP,对吗?
  • 是的,我们正在谈论 TCP。病毒扫描程序不是问题,因为客户端是 iOS 设备,我实际上是通过禁用网络来断开设备的连接。所以它不可能继续工作。

标签: java sockets exception java-io bufferedwriter


【解决方案1】:

为什么不进行接收调用然后捕获异常。如果你得到一个损坏的管道异常或套接字超时,那么你就知道客户端不再存在。

对于这种情况,典型的做法是让服务器使用 setKeepAlive 和 getKeepAlive 方法设置 TCP keepalive。 http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html 。如果客户端离开了,那么 TCP keepalive 将启动(因为不活动)并且它会检测到客户端已断开连接。然后,它将关闭连接。任何后续的 recv() 调用都将返回 -1 值和错误指示。

【讨论】:

  • 非常感谢您的回答,由于我在网上找到的一些信息,由于发送 ping 数据包的间隔约为 2 小时(取决于平台),因此 KeepAlive 毫无意义。我需要在大约 1-5 秒内做出反应。
  • 我同意。我希望 Java 的 setKeepAlive 方法提供了一个选项来调整这些值。但是,您始终可以调整操作系统的全局值。例如,在 Linux 中,可以将这些参数设置为更小的值。这里:tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO 如果你使用的是非 Linux,你可能需要做一些类似的研究。但是,这些设置会影响所有连接,请记住这一点。
  • 谢谢,但这是个问题 - 我的服务器正在运行更多的服务,其中一些可能不喜欢乱用这些参数
【解决方案2】:

好吧,我终于找到了真正有效的解决方案:

InetAddress addr = InetAddress.getByName("192.168.1.121");
addr.isReachable(1000)

像魅力一样工作,反应非常快。事实上,我将它与套接字一起使用,所以在我的情况下,它的工作方式如下:

new Thread() {
  public void run() {
     while(true) {

        try{
            ArrayList<Socket> arr = new ArrayList(clients.values());
                for(int i=0; i<Main.clients.size(); i++){
                    try
                     {
                        InetAddress addr = InetAddress.getByName(arr.get(i).getInetAddress().toString().replace("/", ""));

                        System.out.println(addr.isReachable(1000));


                     }
                     catch (IOException e)
                     {
                    System.out.println("connection probably lost");
                                    e.printStackTrace();
                      }
                 }
          Thread.sleep(1000);
         } catch (Exception e) { System.out.println("Shit happens: "+e); }
      }}
}.start();

这不是真正优化的代码,而且看起来很糟糕,但你明白了它背后的想法。整个代码用于可达主机检测线程。

【讨论】:

  • 这并不能告诉你客户端是否可用,只告诉你他正在执行的主机是否还在运行。
  • 你明白这段代码是在服务器上执行的吧?而所谓的“主机”在这种情况下是客户端?
  • 如果客户端在防火墙后面,它会给你一个假阴性。 -1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-20
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
相关资源
最近更新 更多