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

Java客户端关闭Socket时抛出SocketException的原因及处理方法

异常触发原因

你代码的执行流程中,当主线程的Scanner检测到输入终止(比如用户按下Ctrl+D/Ctrl+Z结束控制台输入),会退出输入循环进入finally块执行socket.close()操作。但此时你启动的后台读线程仍处于运行状态,正阻塞在in.readLine()调用等待服务端返回数据,socket被关闭后,这个 pending 的IO操作会直接抛出java.net.SocketException: Socket closed异常,这就是报错的来源。

该行为是否属于正常现象

这属于主动关闭资源时的预期正常现象,不属于业务逻辑故障,是JDK Socket实现的标准反馈,仅代表关闭socket时还有未完成的IO操作在运行,不代表客户端运行过程中出现了功能问题。

正确的处理方案
  • 给后台读线程增加退出控制逻辑,替换无边界的while(true)死循环,同时对Socket关闭触发的异常做特殊处理,不用打印冗余错误栈。
  • 关闭socket前先更新线程运行标志,关闭socket后等待读线程安全退出,避免资源泄漏。
  • 增加服务端主动断连的兼容判断,readLine()返回null时代表服务端已经关闭连接,直接退出读循环即可。

修改后的参考代码如下:

public static void main(String[] args) throws UnknownHostException, IOException {
    Socket socket = null;
    AtomicBoolean isRunning = new AtomicBoolean(true);
    Thread readThread = null;
    try {
        socket = new Socket("localhost", 9101);
        PrintWriter out = new PrintWriter(socket.getOutputStream());
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        readThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(isRunning.get()) {
                    try {
                        String line = in.readLine();
                        // 服务端主动关闭连接时readLine返回null,直接退出
                        if (line == null) {
                            break;
                        }
                        System.out.println(line);
                    } catch (SocketException e) {
                        // 客户端主动关闭socket触发的异常,属于正常退出场景,无需打印错误
                        break;
                    } catch (IOException e) {
                        e.printStackTrace();
                        System.out.println("read error");
                        break;
                    }
                }
            }
        });
        readThread.start();
        
        System.out.println("Write to server:");
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String message = scanner.nextLine(); 
            out.println(message);
            out.flush();
        };
    } finally {
        // 先修改线程运行标志
        isRunning.set(false);
        // 关闭socket
        if (socket != null && !socket.isClosed()) {
            socket.close();
        }
        // 等待读线程安全退出
        if (readThread != null) {
            try {
                readThread.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 14:45:01