最近在公司遇到一件奇怪的事情,我司私有协议的业务服务器总是收到奇怪的请求,导致收到的包解包失败。

  这个私有协议原理是先收到一个消息头,再收到一个长度,根据长度得到后边数据的长度,最后再把数据解析为相应的 Bytes 或者字符串,完成解包。

  然而实际却总是收到跟声明情况不符合的数据,特点就是消息头声明了后边数据是一个字符串性质的内容,字节长度是x,但是实际发出的数据字节长度是超过x的,因此发现这个包在理应结束后还是没有遇到结束符号,解包出了问题,这条流已无法继续使用了,只能断开连接。

  可是业务的流量来自于一个私有协议的请求分发服务,相当于网络入口,这个服务的编码程序也是久经使用的,经过内网发向业务服务器,是不会无故发出向下图这样不正确的包啊。(图中 ca 表示一个 String 类型的消息,9c 是长度。但是经过 9c 也解析不到任何有意义的数据)

  不过仔细观察图上的流,我发现字节流里有不寻常的出现了很多 EF BF BD 。这几个字节为什么会突然多这么多?一个字符串出现很多同样的字符是很可疑的。上网搜索,发现这个是 UTF-8 的无效字符,Java 在构造 String 的时候如果遇到了非法的 UTF-8 字符,就会使用 EF BF BD 替换。于是查看请求路由的源码,发现它是在应用层上解开了私有协议,对于收到用户发来的消息头,长度和内容,如果消息是 String 内容,就会使用 UTF-8 把消息内容构造成 String,转发的时候则使用了构造后 String 的 getBytes 写入到流内,而此时的长度跟之前写入的长度根本对不上。所以实际上消息分发服务就已经出了问题,只是这在 String 的构造器上并不抛出异常,因此消息分发服务对此一无所知。

  其实知道问题怎么发生的是最难的,解决问题反而是简单的。