MessageHandler从Socket读取消息头未从起始位置开始的问题排查与修复
问题解答
异常原因
- TCP传输是无边界的字节流模式,你的当前代码没有做消息帧边界校验,只要从流中凑够20字节就直接当做消息头解析,不验证内容合法性,这是核心问题。
- 上一条消息处理时,对应的消息体没有被完整读取消费,导致残留的半截消息体数据留在Socket输入流中,下次调用
readMessageHeader()时就会从残留数据开始读取,最终出现跨消息拼接的错位头。 - 现有逻辑缺少消息头合法性校验步骤:你业务中合法的消息头Var1固定为
0x00000003,但错误读取的头Var1为0x2D646973(对应ASCII字符串"dis-"),明显属于非法值,但代码没有校验直接判定读取成功。
修复方案
- 强制完整消费每条消息的全部内容:每次读取完消息头后,按照头中存储的消息体长度,把完整的消息体全部从输入流中读取完毕,哪怕业务逻辑不需要处理消息体,也要将剩余字节读取丢弃,避免残留数据影响下一条消息的解析。
- 新增消息头合法性校验逻辑:在
readMessageHeader()读取完20字节、解析出msgHead后,增加合法值校验,比如校验Var1是否等于固定值0x00000003、其他字段是否在业务允许的范围内。如果校验不通过,说明当前读取位置错位,执行帧同步逻辑,代码示例如下:
msgHead.readFromStream(reader); // 新增头合法性校验逻辑 if (msgHead.getVar1() != 0x00000003) { LogUtils.warn(thisClass, "Invalid message header, sync frame"); // 丢弃1个字节,下次读取会偏移1位重新尝试匹配头 dataInputStream.read(); return false; }
- 保证输入流读取的独占性:确认整个Socket生命周期内,只有消息处理逻辑会读取对应的
dataInputStream,没有其他业务代码并发或者穿插读取该流,避免人为造成的指针偏移。
内容的提问来源于stack exchange,提问作者Igor_M
相关产品推荐
相关产品推荐

