2011-03-10 406 views
4

我有一个Java TCP服务器,当客户端连接到它时,它会每隔30秒向客户端输出一条消息。严格要求客户端不向服务器发送任何消息,并且服务器不向客户端发送除了30秒间隔消息之外的任何数据。检查Java TCP服务器上的客户端断开连接 - 仅输出

当我断开客户端时,服务器直到下次尝试写入客户端时才会意识到这一点。因此,服务器可能需要30秒才能识别断开连接。

我想要做的是每隔几秒钟检查一次断开而不必等待,但我不确定如何做到这一点,因为a)服务器没有从客户端接收和b)服务器无法发送任何其他数据。请有人能够阐明这一点吗?谢谢。

回答

9

即使您的服务器没有从客户端“接收”,客户端套接字上的非阻塞读取会告诉您无法读取任何内容(如您所期望的),或者客户端已断开连接。

如果您使用的是NIO,您可以简单地使用非阻塞的Selector循环(使用非阻塞套接字),并且只能在30秒内写入。如果SelectionKey可读,并且SocketChannel上的读数返回-1,则您知道客户端已断开连接。

编辑:阻塞的另一种方法是简单地选择30秒超时。任何客户端断开连接都会导致select返回,您将通过读取设备知道哪些客户端会断开连接。您需要在此处做的附加事项是跟踪选择中被阻止的时间,以确定何时在30秒标记上进行写入(设置下一次选择三角洲的超时时间)。

大编辑:交谈MYN下面,提供完整的例子之后:

public static void main(String[] args) throws IOException { 

    ServerSocket serverSocket = null; 
    try { 
     serverSocket = new ServerSocket(4444); 
    } catch (IOException e) { 
     System.err.println("Could not listen on port: 4444."); 
     System.exit(1); 
    } 

    Socket clientSocket = null; 
    try { 
     clientSocket = serverSocket.accept(); 
    } catch (IOException e) { 
     System.err.println("Accept failed."); 
     System.exit(1); 
    } 

    // Set a 1 second timeout on the socket 
    clientSocket.setSoTimeout(1000); 

    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); 
    BufferedReader in = new BufferedReader(
      new InputStreamReader(
      clientSocket.getInputStream())); 

    long myNextOutputTime = System.currentTimeMillis() + 30000; 

    String inputLine = null; 
    boolean connected = true; 
    while (connected) 
    { 
     try { 
      inputLine = in.readLine(); 
      if (inputLine == null) 
      { 
       System.out.println("Client Disconnected!"); 
       connected = false; 
      } 
     } 
     catch(java.net.SocketTimeoutException e) 
     { 
      System.out.println("Timed out trying to read from socket"); 
     } 

     if (connected && (System.currentTimeMillis() - myNextOutputTime > 0)) 
     { 
      out.println("My Message to the client"); 
      myNextOutputTime += 30000; 
     } 


    } 

    out.close(); 
    in.close(); 
    clientSocket.close(); 
    serverSocket.close(); 
} 

这里值得注意的是,PrintWriter真正感动你远离实际的插座上,你不会在写入时捕获套接字断开连接(它永远不会抛出异常,您必须使用checkError()手动检查它)您可以更改为使用BufferedWriter(需要使用flush()推送输出)并像处理它一样处理它,以便捕获迪斯科在写。

+0

+1或者,换句话说,你必须轮询,说一秒钟,一个非阻塞阅读。 – 2011-03-10 17:47:44

+0

谢谢Brian。我没有使用NIO,是否仍然可以使用非阻塞式读取?我也尝试过使用'setSoTimeout()',但是当我强迫客户端关闭时,这似乎不起作用,这是我的测试之一。 – Myn 2011-03-11 09:59:29

+0

是否有你不使用NIO的原因?它自2002年以来一直存在,真正让你的问题变得微不足道。我很久没有想到我们在NIO之前如何做到这一点;查看它之前没有一个真正的非阻塞读取或一个'select()'。你用'setSoTimeout()'来正确的轨道,因为这是你拥有的唯一途径。你应该可以在你的socket读取之前调用它,如果它超时,它会抛出一个'InterruptedIOException'。相当混乱,但 - 如果你可以使用NIO,我可以给你一个它如何工作的例子。 – 2011-03-11 15:51:56

1

如果你正在管理多个客户端,那么我想你会使用非阻塞套接字(如果没有,那么考虑使用非阻塞)。您可以使用选择器来监视所有连接的套接字,以检查它们是可读的还是可写的,或者该套接字上是否存在错误。当某些客户端断开连接时,您的选择器将标记该套接字并返回。 更多帮助谷歌“套接字选择功能”

相关问题