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

读取BufferedReader时触发java.net.SocketException连接重置问题

Socket连接重置异常与数据接收问题分析与解决

问题详情

从BufferedReader读取行数据时抛出java.io.UncheckedIOException,底层触发java.net.SocketException: Connection reset异常,完整栈追踪如下:

Exception in thread "Thread-7" java.io.UncheckedIOException: java.net.SocketException: 
Connection reset
at java.io.BufferedReader$1.hasNext(BufferedReader.java:574)
at java.util.Iterator.forEachRemaining(Iterator.java:115)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at net.custompayload.LunarRAT.handler.PacketHandler.Packet(PacketHandler.java:31)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at java.io.BufferedReader$1.hasNext(BufferedReader.java:571)
... 9 more

进程最终以退出码130终止,同时存在客户端发送数据后服务器无法接收的问题。当前处理逻辑代码如下:

reader = new BufferedReader(new InputStreamReader(_socket.getInputStream(), 
StandardCharsets.UTF_8));
reader.ready();
String data = reader.lines().collect(Collectors.joining());
if(data != null && !data.isEmpty()){
    ArrayList<String> args = StringUtils.ConvertStringToArrayListArguments(data);
    for(String module : Module.Modules.keySet()){
        String name = Module.Modules.get(module).getName();
        if(data.equalsIgnoreCase(name)){
            Module.Modules.get(module).Execute(args);
        }
    }
}

问题根源

  1. Connection reset异常:这种异常一般是连接的客户端突然断开(比如崩溃、强制关闭、网络中断),服务器此时尝试从已失效的Socket流读取数据,就会触发该异常。
  2. 数据接收失败:
    • reader.ready()调用完全多余,这个方法仅判断流是否有可读取数据,不会阻塞,对后续读取逻辑没有帮助。
    • reader.lines().collect(Collectors.joining())会一直阻塞读取,直到Socket输入流关闭(即客户端断开连接)。如果客户端发送数据后没关闭输出流,服务器会一直卡在读取步骤,直到客户端断开才抛出异常,看起来像是没接收到数据。
    • 模块匹配逻辑有问题:用拼接后的完整数据和模块名称做全匹配,若客户端发送的是带参数的内容,永远无法匹配成功,导致逻辑不执行,误以为没收到数据。

解决办法

1. 捕获异常并清理资源

给读取代码加上异常捕获,避免线程因异常直接终止,同时确保Socket和流资源被正确关闭:

try {
    reader = new BufferedReader(new InputStreamReader(_socket.getInputStream(), StandardCharsets.UTF_8));
    // 移除无意义的reader.ready()
    String data = reader.lines().collect(Collectors.joining());
    if(data != null && !data.isEmpty()){
        ArrayList<String> args = StringUtils.ConvertStringToArrayListArguments(data);
        for(String moduleKey : Module.Modules.keySet()){
            Module module = Module.Modules.get(moduleKey);
            if(module.getName().equalsIgnoreCase(data)){
                module.Execute(args);
                break; // 匹配到后直接退出循环,提升效率
            }
        }
    }
} catch (UncheckedIOException e) {
    System.err.println("连接已被重置: " + e.getCause().getMessage());
} finally {
    // 确保资源关闭
    try {
        if(reader != null) reader.close();
        if(_socket != null) _socket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2. 修正数据读取逻辑

不要依赖流关闭来结束读取,定义明确的通信协议:

  • 用换行符作为数据结束标记:客户端发送数据后加上换行,服务器用readLine()读取单行数据,避免阻塞:
    String data = reader.readLine();
    if(data != null && !data.isEmpty()){
        // 后续处理逻辑
    }
    
  • 调整模块匹配逻辑:如果客户端发送的是「模块名+参数」格式,先拆分出模块名再匹配:
    if(data != null && !data.isEmpty()){
        // 按空格拆分,最多拆成两部分(模块名+参数)
        String[] parts = data.split("\\s+", 2);
        if(parts.length == 0) return;
        
        String targetModuleName = parts[0];
        ArrayList<String> args = new ArrayList<>();
        if(parts.length > 1){
            args = StringUtils.ConvertStringToArrayListArguments(parts[1]);
        }
        
        // 遍历模块匹配
        for(String moduleKey : Module.Modules.keySet()){
            Module module = Module.Modules.get(moduleKey);
            if(module.getName().equalsIgnoreCase(targetModuleName)){
                module.Execute(args);
                break;
            }
        }
    }
    

3. 退出码130说明

退出码130通常是进程被用户通过Ctrl+C手动中断导致,若不是手动终止,需检查是否是异常连锁引发的进程退出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 07:48:42