读取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); } } }
问题根源
- Connection reset异常:这种异常一般是连接的客户端突然断开(比如崩溃、强制关闭、网络中断),服务器此时尝试从已失效的Socket流读取数据,就会触发该异常。
- 数据接收失败:
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
相关产品推荐
相关产品推荐

