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

ObjectInputStream readObject触发SocketClosed异常的问题排查

问题根源:误用Kotlin的use函数导致Socket被自动关闭

你的问题出在客户端和服务端都误用了Kotlin的use扩展函数——这个函数的核心作用是自动实现资源的关闭(因为ObjectInputStream和ObjectOutputStream都实现了AutoCloseable接口),当use代码块执行完毕后,它会自动调用流的close()方法,而关闭这些对象流会连带关闭底层的Socket连接,导致后续的读取/写入操作抛出SocketClosed异常。

具体分析:

  1. 客户端侧:当你执行writer.use { ... }时,代码块写完对象并flush后,use会立刻关闭ObjectOutputStream。关闭这个流会导致关联的Socket输出流被关闭,进而整个Socket连接进入关闭状态。
  2. 服务端侧:第一次读取对象时,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:14:54