如何检测远程端口的关闭?

88

如何检测远程套接字上是否已调用Socket#close()

4个回答

65

isConnected 方法没用,即使远程端关闭了套接字,它也会返回 true。试试这个:

public class MyServer {
    public static final int PORT = 12345;
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(PORT);
        Socket s = ss.accept();
        Thread.sleep(5000);
        ss.close();
        s.close();
    }
}

public class MyClient {
    public static void main(String[] args) throws IOException, InterruptedException {
        Socket s = SocketFactory.getDefault().createSocket("localhost", MyServer.PORT);
        System.out.println(" connected: " + s.isConnected());
        Thread.sleep(10000);
        System.out.println(" connected: " + s.isConnected());
    }
}

启动服务器,启动客户端。你会看到它打印了 "connected: true" 两次,即使第二次套接字已关闭。

真正找出答案的唯一方法是通过读取(将返回-1)或写入(将抛出IOException(破损的管道))关联的输入/输出流。


1
在你的例子中,服务器没有优雅地关闭TCP连接(发送RST并结束)。如果在客户端套接字上调用close(),则连接将被优雅地关闭。您可以通过读操作的不同结果来看到这一点:抛出SocketException与读取返回-1。 - Alexander
4
唯一的获取答案的方式是撰写代码。从一个突然关闭的套接字中读取数据并不总是返回-1。https://dev59.com/-Gw15IYBdhLWcg3wxunL#6404085 - Bruno
@Bruno 请详细说明为什么一个关闭的套接字可能并不总是返回-1。 - Pacerier
1
@Pacerier,看我发的链接。本质上,如果你没有使用TCP keep-alive,那么一个不发送任何内容的连接和一个已经关闭的连接是没有区别的。你只能通过向其写入数据来检测到一个关闭的连接。 - Bruno
15
这为什么有那么多点赞啊 :/ 它实际上甚至没有回答问题,只是在解释“什么行不通”... - Matt Clark
显示剩余2条评论

30

由于答案有所偏离,我决定测试一下并发布结果 - 包括测试示例。

这里的服务器只是向客户端写入数据,不需要任何输入。

服务器代码如下:

ServerSocket serverSocket = new ServerSocket(4444);
Socket clientSocket = serverSocket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
while (true) {
  out.println("output");
  if (out.checkError()) System.out.println("ERROR writing data to socket !!!");
  System.out.println(clientSocket.isConnected());
  System.out.println(clientSocket.getInputStream().read());
        // thread sleep ...
  // break condition , close sockets and the like ...
}
  • 一旦客户端连接(即使在断开连接后),clientSocket.isConnected()总是返回true,这很奇怪!
  • getInputStream().read()会导致线程一直等待输入,只要客户端保持连接,因此会导致程序除非获得一些输入,否则不会做任何事情。如果客户端断开连接,则返回-1。
  • out.checkError()在客户端断开连接后立即变为true,因此我建议使用它

27
只有在发生写入错误时,checkError() 才会立即变为 true,而不是在客户端断开连接之后立即变为 true。请注意,这个函数的返回值并不受客户端连接状态的影响。-1 - user207421

13

在向客户端套接字写入数据时,您还可以检查套接字输出流的错误。

out.println(output);
if(out.checkError())
{
    throw new Exception("Error transmitting data.");
}

3
可以做到,但不一定会立即理解。 - user207421

-12

如果远程系统已断开/关闭连接,则方法Socket.Available将立即抛出SocketException。


10
不会的。错误的。不正确的。误导信息。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接