You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

复用Socket时抛出java.net.SocketException: Socket is closed问题求助

Socket复用失败问题解决

问题场景

尝试复用同一个Socket向WHOIS服务多次发送查询请求,但第一次请求后抛出java.net.SocketException: Socket is closed异常。

原测试代码

private final static String WHOIS_HOST = "whois.verisign-grs.com";
private final static int WHOIS_PORT = 43;

@Test
void justAnExample() {

    try {

        Socket socket = new Socket(WHOIS_HOST, WHOIS_PORT);
        socket.setSoTimeout(5000);

        sendRequest(socket, "cnn.com");

        Thread.sleep(2000);

        sendRequest(socket, "youtube.com");

        Thread.sleep(2000);

        sendRequest(socket, "toyota.com");

        socket.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void sendRequest(Socket socket, String domain) throws IOException {

    OutputStream out = socket.getOutputStream();
    out.write((domain + "\r\n").getBytes());

    try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
        String line;
        while ((line = input.readLine()) != null) {
            if (line.contains("Registry Expiry Date")) {
                line = line.substring(line.indexOf(':') + 1).trim();
                System.out.println("---> " + line);
                break; // don't need to read any more input
            }
        }

        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
        if(line != null){
            final LocalDateTime dt = LocalDateTime.parse(line, formatter);
            System.out.println("---> " + dt);
            System.out.println("---> Not available " + domain);

        } else {
            System.out.println("---> Available " + domain);
        }
    }

    out.flush();
    out.close();
}

运行异常

---> 2026-09-21T04:00:00Z
---> 2026-09-21T04:00
---> Not available cnn.com
java.net.SocketException: Socket is closed
    at java.base/java.net.Socket.getOutputStream(Socket.java:998)

问题原因及解决方案

1. 核心问题:过早关闭Socket输出流

在sendRequest方法最后调用了out.close(),关闭输出流时会直接关闭底层的Socket连接,导致后续无法再复用该Socket。

2. 修改步骤

步骤一:移除out.close()调用

保留out.flush()确保数据发送,但不要关闭输出流,Socket的关闭统一放到所有请求完成后执行。

步骤二:读取完整响应,避免残留数据

第一次请求时只读取到目标行就终止,WHOIS服务返回的剩余响应数据会留在输入流中,导致后续请求解析异常。需要读取完整响应内容,清空输入流。

修改后的sendRequest方法

private void sendRequest(Socket socket, String domain) throws IOException {
    OutputStream out = socket.getOutputStream();
    out.write((domain + "\r\n").getBytes());
    out.flush(); // 立即发送请求数据

    try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
        String line;
        String expiryLine = null;
        // 读取完整响应,筛选目标信息
        while ((line = input.readLine()) != null) {
            if (line.contains("Registry Expiry Date")) {
                expiryLine = line.substring(line.indexOf(':') + 1).trim();
                System.out.println("---> " + expiryLine);
            }
        }

        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
        if(expiryLine != null){
            final LocalDateTime dt = LocalDateTime.parse(expiryLine, formatter);
            System.out.println("---> " + dt);
            System.out.println("---> Not available " + domain);

        } else {
            System.out.println("---> Available " + domain);
        }
    }
    // 不关闭OutputStream,Socket统一在所有请求完成后关闭
}

3. 额外注意事项

  • 部分WHOIS服务可能在一段时间无操作后主动断开持久连接,建议添加异常捕获逻辑,在连接断开时重新创建Socket。
  • 可以在初始化Socket时一次性获取OutputStream并复用,减少重复获取的资源开销。

内容的提问来源于stack exchange,提问作者Peter Penzov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 20:42:10