Gooddbird / tinyrpc

c++ async rpc framework. 14w+qps.
Apache License 2.0
1.26k stars 189 forks source link

关于tinypb协议的疑问 #44

Closed piaodazhu closed 1 year ago

piaodazhu commented 1 year ago

您好,我看到业务接口是通过.proto文件定义的,我的理解是protobuf根据这个文件来做序列化反序列化。但是tinypb实际上也自己规定了一些字段,其中就包含了.proto消息序列化后的字符串,而tinypb在代码里是手动序列化反序列化的。我的问题是,为什么不直接全部用protobuf来处理rpc通信的消息,而要在外层封装一层tinypb还要手动序列化呢?

(刚接触rpc,之前没有实际业务经验,目前正在通过您的项目学习这一块的内容。)

Gooddbird commented 1 year ago

你好,因为protobuf序列化之后完全是字节流的,如果客户端一次向服务端发送了多个RPC请求,每一个请求是一个protobuf的序列化后的字节流,但是你没办法拆分请求,因为你的每个请求没有起始或者结束的标识符,所以没办法划分。 举个简单例子,假设请求A序列化后是 ABC,请求B序列化后是 EFG。当一起发送到服务端时,服务端收到的是 ABCDEF,此时服务端如何解析数据呢?它根本不知道这是一个请求包还是两个请求包(甚至可以是一个半)。所以需要在 protobuf 序列化之后再加一些自定义的字段。 比如每个请求,我用^ 字符表示开始,$字符表示结束。那么服务端收到的就是 ^ABC$^DEF, 就可以通过 ^ $ 这两个开始结束符来分割每个数据包了。这就是为什么要加开始符号。另外也需要一个id来标识每一个请求和响应,使请求响应一一对于,所以需要加消息号。其他的错误码等字段也是同理,再加个长度字段方便校验

除此之外,还有一个重要的原因。protobuf 序列化的结果是不含请求方法(method name) 的,也就是说服务端根本无法判断这个RPC请求调用的是哪个方法。所以必须把method name 封装到请求体里面。