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

Socket助手类中try/catch无法捕获ENETUNREACH错误问题

问题分析与解决方案

核心原因

崩溃根源是basicSendToUDP()中UDP send调用抛出的ENETUNREACH(网络不可达)异常未在当前执行线程中被捕获——你添加的catch块仅覆盖了Socket助手的启动代码(主线程或启动线程),但send操作在子线程中执行,子线程的异常无法被启动线程的catch捕获。

代码修复方案

1. 在basicSendToUDP()方法内直接捕获异常

不管send操作在哪个线程执行,最稳妥的方式是在调用send的方法内部直接覆盖所有可能的IO异常:

// 修改后的basicSendToUDP()方法
public void basicSendToUDP(byte[] data, InetAddress address, int port) {
    if (socket == null) {
        return;
    }
    try {
        socket.send(new DatagramPacket(data, data.length, address, port));
    } catch (IOException e) {
        // 捕获所有IO异常,包含ENETUNREACH
        if (e.getMessage().contains("ENETUNREACH")) {
            // 网络不可达的针对性处理
            Log.e("UDP", "Network unreachable: " + e.getMessage());
        } else if (e instanceof PortUnreachableException) {
            // 端口不可达的特殊处理
            Log.e("UDP", "Port unreachable: " + e.getMessage());
        } else {
            // 其他IO异常兜底处理
            Log.e("UDP", "Send failed: " + e.getMessage());
        }
    } catch (Exception e) {
        // 捕获所有未预料的异常,避免崩溃
        Log.e("UDP", "Unexpected send error: " + e.getMessage());
    }
}

2. 给子线程添加未捕获异常处理器(可选)

如果UDP发送在自定义线程中执行,除了方法内捕获,还可以给线程设置全局异常处理器,防止遗漏的异常导致崩溃:

// 自定义发送线程示例
public class UdpSendThread extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            // UDP发送循环逻辑
            while (!isInterrupted()) {
                basicSendToUDP(data, address, port);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.e("UDPThread", "Thread interrupted: " + e.getMessage());
        }
    }

    // 初始化时绑定未捕获异常处理器
    public UdpSendThread() {
        setUncaughtExceptionHandler((thread, throwable) -> {
            Log.e("UDPThread", "Uncaught exception in send thread: " + throwable.getMessage());
            // 可在此添加线程重启或恢复逻辑
        });
    }
}

3. 修正启动代码的catch范围

你之前在启动代码中添加的catch块,仅能捕获线程启动阶段的异常,无法覆盖线程运行时的send异常。启动代码的正确写法参考:

// Socket助手启动代码示例
public void startUdpClient() {
    try {
        // 初始化Socket
        socket = new DatagramSocket();
        // 启动发送线程
        UdpSendThread sendThread = new UdpSendThread();
        sendThread.start();
    } catch (SocketException e) {
        // 仅捕获Socket初始化时的异常
        Log.e("UdpHelper", "Failed to create socket: " + e.getMessage());
    }
    // 注意:此处catch无法捕获sendThread.run()中的异常
}

关键说明

  • ENETUNREACH属于系统级网络异常,是IOException的子类,部分系统会以SocketException形式抛出,捕获IOException可覆盖这类异常。
  • 父线程的catch块无法捕获子线程异常,子线程异常必须在自身线程内部处理,或通过UncaughtExceptionHandler统一处理。
  • 测试时可模拟网络断开场景,验证异常捕获逻辑是否生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:33:24