ObjectInputStream readObject触发SocketClosed异常的问题排查
问题根源:误用Kotlin的
use函数导致Socket被自动关闭 你的问题出在客户端和服务端都误用了Kotlin的use扩展函数——这个函数的核心作用是自动实现资源的关闭(因为ObjectInputStream和ObjectOutputStream都实现了AutoCloseable接口),当use代码块执行完毕后,它会自动调用流的close()方法,而关闭这些对象流会连带关闭底层的Socket连接,导致后续的读取/写入操作抛出SocketClosed异常。
具体分析:
- 客户端侧:当你执行
writer.use { ... }时,代码块写完对象并flush后,use会立刻关闭ObjectOutputStream。关闭这个流会导致关联的Socket输出流被关闭,进而整个Socket连接进入关闭状态。 - 服务端侧:第一次读取对象时,
reader.use { ... }执行完后,同样会关闭ObjectInputStream,这也会触发Socket连接的关闭。所以即使客户端没主动关,服务端这边的流关闭也会导致Socket断开,后续循环里的readObject()自然就会抛出异常。
而你换成普通流时没问题,是因为:
- 客户端没有用
use,只是写入字节数组,没关闭输出流; - 服务端用的
Scanner不会自动关闭底层的输入流,所以Socket连接能保持存活。
修复方案:移除use函数,手动管理资源关闭
你需要去掉use块,直接调用流的方法,直到真正需要断开连接时,再在shutdown方法里统一关闭流和Socket。
修改后的客户端代码片段:
fun run() { var sent = false while (connected) { try { if (!sent) { sent = true writer.writeObject("Hello") writer.flush() println("Sent") } else { println("Didn't send") } Thread.sleep(1000) } catch (ex: Exception) { ex.printStackTrace() shutdown() } } } // 补充shutdown方法里的资源关闭 fun shutdown() { connected = false try { reader.close() writer.close() connection.close() } catch (e: IOException) { e.printStackTrace() } }
修改后的服务端代码片段:
fun run() { running = true while (running) { try { val packet = reader.readObject() when (packet) { is String -> { println("Received packet with data: ${packet}") } } } catch (ex: Exception) { ex.printStackTrace() shutdown() } } } // 补充shutdown方法里的资源关闭 fun shutdown() { running = false try { reader.close() writer.close() client.close() } catch (e: IOException) { e.printStackTrace() } }
验证效果
修改后,客户端的流不会被自动关闭,Socket连接保持存活;服务端第一次读取后也不会关闭流,后续循环可以正常等待新的对象(当然你后续可以扩展客户端发送更多对象)。此时服务端不会再抛出SocketClosed异常,连接能稳定保持。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

