iohao / ioGame

无锁异步化、事件驱动架构设计的 java netty 网络编程框架; 轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式; 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景; 通过 ioGame 你可以很容易的搭建出一个集群无中心节点、集群自动化、分布式的网络服务器;FXGL、Unity、UE、Cocos Creator、Godot、Netty、Protobuf、webSocket、tcp、socket;java Netty 游戏服务器框架;
http://game.iohao.com
GNU Affero General Public License v3.0
904 stars 201 forks source link

jprotobuf默认值丢失问题 #190

Closed chenmaochang closed 1 year ago

chenmaochang commented 1 year ago

原生protobuf的序列化,在proto3的版本,如果属性值是默认值,是不传递数据的,也就是说一个下面这样的proto文件

syntax = "proto3";
package com.demo;

message DemoMsg {
  int32 id = 1;
}

它如果id传了个0,按谷歌原生protobuf的协议规则这个proto最后序列化出来什么也没有,一个字节都没有,因为原生的反序列化如果将0字节反序列化成DemoMsg,将会得到一个id的值是0(默认值)的对象 但百度的jprotobuf的反序列化不会这么做,当0字节进行反序列化时,不会对任何字段进行设值,byte[]类型也就没有默认值了(原本应该要有一个new byte[0]) 最最最最终就导致,如果我传入的DemoMsg它的id是0,那么ioGame的ExternalMessage这个类的data属性(byte[]类型)会是null,而不是new byte[0],然后就会反序列化出一个DemoMsg=null 这个问题在当前的jprotobuf2.4.18中仍然存在,并且百度还没想要修复的意思

但是ioGame推荐jprotobuf作为简化protobuf的使用,插件有重大问题时,也提供集成原生的demo给其他开发者会更好,这个bug其实还是很容易就发现了,比如传入的参数是个布尔值或是个枚举,或者二者都有,然后值全是默认值就能100%触发到

iohao commented 1 year ago

186

或使用 17.1.55 版本

iohao commented 1 year ago
message DemoMsg {
  int32 id = 1;
}

插个题外话,如果项目中存在较多类似 DemoMsg 这样的结构,可以考虑使用框架提供的解决协议碎片特性。

该特性提供了自动装箱、拆箱基础类型,开始可能用不习惯;但用了几次之后,基本会触发真香定律。