使用Java Socket时需关闭哪些资源?Socket.close()的作用
关于Java Socket Connection类close方法的资源关闭问题
首先明确两个核心点:
调用socket.close()时自动关闭的资源
当你调用socket.close()时,JDK会自动关闭Socket关联的原始输入/输出字节流——也就是socket.getInputStream()和socket.getOutputStream()直接返回的那两个字节流。但要注意:
- 这不会自动关闭基于这些原始流包装的上层处理流(比如你代码里的PrintWriter、BufferedReader、ObjectOutputStream这些)
- 也不会触发上层处理流的缓冲区刷新操作,可能导致残留数据丢失
需要手动关闭的资源
你必须手动关闭所有基于原始流包装的处理流实例:
out(PrintWriter):即使构造时开启了自动刷新,关闭操作仍会确保所有缓冲区数据写入底层流,避免遗漏in(BufferedReader):释放其内部缓冲区资源objectOut(ObjectOutputStream):非常关键,关闭时会自动完成序列化数据的缓冲区刷新,确保所有对象数据都写入Socket输出流,不关闭的话可能导致对方收不到完整的序列化对象objectIn(ObjectInputStream):释放其关联的资源
注意事项
- 关闭顺序:应该先关闭输出相关的流(
objectOut、out),再关闭输入相关的流(objectIn、in),最后关闭Socket。这样能避免因输入流先关闭导致输出流写入失败的问题。 - 异常处理:每个流的
close()都可能抛出IOException,建议逐个捕获异常,避免一个流关闭失败导致后续资源无法释放。比如你当前的代码在调用socket.close()后再关闭其他流,大概率会抛出异常(因为底层流已被Socket关闭),这是不合理的。
优化后的close方法示例
public void close() { // 先关闭输出流 try { if (objectOut != null) objectOut.close(); } catch (IOException e) { // 记录日志或处理异常 } try { if (out != null) out.close(); } catch (Exception e) { // PrintWriter的close不会抛IOException,但还是处理下 } // 再关闭输入流 try { if (objectIn != null) objectIn.close(); } catch (IOException e) { // 记录日志或处理异常 } try { if (in != null) in.close(); } catch (IOException e) { // 记录日志或处理异常 } // 最后关闭Socket try { if (socket != null && !socket.isClosed()) socket.close(); } catch (IOException e) { // 记录日志或处理异常 } }
或者更简洁的try-with-resources方式(让Connection实现AutoCloseable接口):
public class Connection implements AutoCloseable { // ... 原有成员变量与构造方法 ... @Override public void close() throws IOException { try (ObjectOutputStream oOut = objectOut; PrintWriter pOut = out; ObjectInputStream oIn = objectIn; BufferedReader bIn = in; Socket s = socket) { // try-with-resources会自动按逆序关闭所有资源 } } }
内容的提问来源于stack exchange,提问作者VictoRPiles
相关产品推荐
相关产品推荐

