Java通过WebSocket发送XML/JSON时使用ByteArrayOutputStream的优势
Java WebSocket传输中使用ByteArrayOutputStream转字节流对比直接发送String的优势
Java原生WebSocket规范(JSR 356)支持文本帧、二进制帧两种传输模式,两类传输方式的核心差异集中在序列化效率、资源占用、兼容性三个维度,使用ByteArrayOutputStream转字节流发送XML、JSON数据的具体优势如下:
- 更低的序列化开销
直接传输String本质会经历两次冗余编码:你把XML/JSON序列化为String时,JVM内部已经按UTF-16格式存储字符串,后续WebSocket实现类发送文本帧时,还需要把UTF-16的String转成UTF-8字节序列再走网络传输。如果用ByteArrayOutputStream,在序列化XML/JSON的阶段就可以直接输出UTF-8字节,省去了中间UTF-16字符串生成、编码转换的步骤,大体积文档场景下性能提升非常明显。
比如用Jackson序列化JSON时,直接调用writeValue(OutputStream out, Object value)写ByteArrayOutputStream,比先调用writeValueAsString得到String再发送,内存占用能降低30%以上。 - 避免隐式编码兼容问题
String传输依赖WebSocket两端默认的编码配置,如果服务端或客户端某一端不按规范使用UTF-8,私自修改默认文本编码(比如改成GBK),就会出现乱码。而字节流传输的编码规则完全由业务侧控制,写入ByteArrayOutputStream时就指定UTF-8编码,只要两端约定一致,不会出现隐式的编码兼容问题。 - 更灵活的传输扩展能力
字节流模式下可以很方便的在发送前做额外处理,比如对XML/JSON做gzip压缩、加校验和、加密,不需要再做额外的String<->字节的转换。如果用String传输,压缩或者加密后得到的还是字节,最终还是要转成二进制帧发送,多了不必要的转换步骤。 - 更低的内存与GC压力
大体积的XML/JSON文档如果先转成String,会在堆内存里完整生成一份UTF-16的字符串副本,而ByteArrayOutputStream可以做到边序列化边写缓存,甚至配合流式API不用把完整的文档全部加载到内存里,大文件传输场景下GC压力小很多。 - 适配二进制帧的传输特性
WebSocket的二进制帧没有文本帧的UTF-8合法性校验步骤,传输时不需要扫描字节序列判断是否为合法UTF-8字符,传输和解析速度更快。而且多数网关、代理对二进制帧的传输优先级更高,公网传输丢包率更低。
内容的提问来源于stack exchange,提问作者Johnny boy
相关产品推荐
相关产品推荐

