Android与Java服务端对象流通信随机触发unexpected EOF异常
问题原因
- 核心原因是两端读写协议不匹配:服务端代码残留了未注释的冗余写入逻辑
if (verification)out.writeChar('Y');:
当权限校验通过(verification=true)时,服务端会先向输出流写入2字节的char类型值'Y',再写入1字节的boolean类型校验结果,累计写出3字节;当校验不通过时,服务端不会写入char值,仅写出1字节的boolean值。但客户端固定只调用in.readBoolean()读取1字节内容,直接导致流读取指针错位:一旦出现多写的字节,后续所有序列化数据的解析都会偏移,触发java.io.StreamCorruptedException,由于错位只在校验通过等特定场景触发,因此表现为随机崩溃、非必现。 - 次要原因是构建缓存残留:从错误堆栈可以看到崩溃点在
readChar方法,和贴出的客户端调用readBoolean的逻辑不符,说明Android Studio构建时可能残留了旧版本的客户端代码(之前注释掉的readChar逻辑),进一步加剧了读写逻辑不匹配的概率。 - 潜在隐患是流的并发操作问题:
ObjectInputStream/ObjectOutputStream本身不是线程安全的,长连接场景下如果多个线程同时读写流、没有加同步锁,会出现写入数据交错、流内部缓存损坏,同样会触发流损坏异常。
修复方案
- 对齐两端读写协议:彻底删除服务端残留的冗余写入代码,删除
if (verification)out.writeChar('Y');行以及注释掉的writeChar('N')相关代码,仅保留固定写入boolean值的逻辑,保证无论校验结果是true还是false,服务端都只向流写入1字节的boolean值,和客户端的读取逻辑完全对应。修正后的服务端写入逻辑如下:System.out.println("WOW"); System.out.println(verification); out.writeBoolean(verification); out.flush(); System.out.println("WOW"); - 清理构建缓存:在Android Studio中依次执行
Build > Clean Project、Build > Rebuild Project,卸载设备上已安装的旧版本APK后重新安装,彻底清除旧版本代码残留,保证运行的客户端逻辑和当前编写的代码一致。 - 加锁保证流操作的线程安全:为Socket对应的输入、输出流创建全局锁对象,所有读写流的操作都放在同步代码块中执行,避免多线程并发操作导致流数据交错。示例代码:
// 连接初始化时创建全局锁对象 private final Object socketIoLock = new Object(); // 所有写流操作包裹在同步块中 synchronized (socketIoLock) { out.writeObject(sendData); out.flush(); } // 所有读流操作包裹在同步块中 synchronized (socketIoLock) { Object receiveData = in.readObject(); } - 可选优化:Java原生Object序列化存在性能差、跨端兼容性弱、版本强绑定的问题,即时通讯长连接场景建议替换为Protobuf等轻量、跨语言的序列化协议,从根源上减少序列化解析异常。
内容的提问来源于stack exchange,提问作者giannismparous
相关产品推荐
相关产品推荐

