在 ZeroMQ 中使用 Protocol Buffers 实现 RPC
Using Protocol Buffers for implementing RPC in ZeroMQ
我有一个简单的设置,一个客户端和一个服务器。客户端想要使用 ZeroMQ 进行通信在服务器中执行一个方法。我将使用 REQ 和 REP 套接字,因为它们适用于此用例。不过我对 protobuf 的定义有疑问。我认为这两个选项可以用来实现目标:
message ControlService{
string control = 1;
int32 serverId = 2;
bool block = 3;
double temperature = 4;
}
其中 "control" 包含要远程执行的方法的名称。另一种选择可以是:
message InputParameters{
int32 serverId = 1;
bool block = 2;
double temperature = 3;
}
message Empty{
}
service ControlService{
rpc control (InputParameters) returns (Empty);
}
最好的方法是什么?或者至少使用一种方法而不是另一种方法的权衡是什么?
不要那样做。有留言:
message InputParameters{
req oneof
{
InputParametersA a = 1;
InputParametersB b = 2;
}
}
message InputParametersA
{
bool block = 1;
float temperature = 2;
}
message InputParametersB
{
<more fields>
}
这样您只发送 InputParameters 消息。要调用的方法取决于 InputParameters.req 是否包含 InputParametersA(暗示应调用方法 A)或 InputParmetersB(对于方法 B)。
这避免了解析字符串以确定方法名称(极易出错),而是为您提供一个枚举以打开(req 字段的可能内容)。根据您使用的 GPB 的实现(C++ 等),如果您的 switch 语句没有充分涵盖该枚举的所有值,您甚至可能会收到编译时警告。
这也意味着确定应该将哪些字段传递给方法没有问题;您将 InputParameters.req.a 传递给方法 A 或将 .b 传递给方法 B。无需将它们分解为方法的单独参数,只需将整个参数作为单个参数传递即可。
您可以用相同的方式定义不同的 return 类型,通过单个 oneof
.
将它们全部传回
备选方案
现在,如果您使用的是 ASN.1(在概念上与 GPB 是同一种东西),您可以对消息字段的值和/或大小设置约束(参见 here, Chapter 13 in this PDF。这样您将自动执行参数验证,仅在 ASN.1 架构中定义。GPB 中缺少值/大小限制是一个明显的遗漏。
看看here (overview), here (free schema compiler for C/C++ that looks OK), and here (PDF, reference manual).
ASN.1 的有线格式具有更强的类型(如果您使用 BER 编码)。可以询问有线比特流以找出它包含什么类型的消息。因此,无需像使用 GPB 那样将所有可能的消息包装到一个 oneof
中。
我有一个简单的设置,一个客户端和一个服务器。客户端想要使用 ZeroMQ 进行通信在服务器中执行一个方法。我将使用 REQ 和 REP 套接字,因为它们适用于此用例。不过我对 protobuf 的定义有疑问。我认为这两个选项可以用来实现目标:
message ControlService{
string control = 1;
int32 serverId = 2;
bool block = 3;
double temperature = 4;
}
其中 "control" 包含要远程执行的方法的名称。另一种选择可以是:
message InputParameters{
int32 serverId = 1;
bool block = 2;
double temperature = 3;
}
message Empty{
}
service ControlService{
rpc control (InputParameters) returns (Empty);
}
最好的方法是什么?或者至少使用一种方法而不是另一种方法的权衡是什么?
不要那样做。有留言:
message InputParameters{
req oneof
{
InputParametersA a = 1;
InputParametersB b = 2;
}
}
message InputParametersA
{
bool block = 1;
float temperature = 2;
}
message InputParametersB
{
<more fields>
}
这样您只发送 InputParameters 消息。要调用的方法取决于 InputParameters.req 是否包含 InputParametersA(暗示应调用方法 A)或 InputParmetersB(对于方法 B)。
这避免了解析字符串以确定方法名称(极易出错),而是为您提供一个枚举以打开(req 字段的可能内容)。根据您使用的 GPB 的实现(C++ 等),如果您的 switch 语句没有充分涵盖该枚举的所有值,您甚至可能会收到编译时警告。
这也意味着确定应该将哪些字段传递给方法没有问题;您将 InputParameters.req.a 传递给方法 A 或将 .b 传递给方法 B。无需将它们分解为方法的单独参数,只需将整个参数作为单个参数传递即可。
您可以用相同的方式定义不同的 return 类型,通过单个 oneof
.
备选方案
现在,如果您使用的是 ASN.1(在概念上与 GPB 是同一种东西),您可以对消息字段的值和/或大小设置约束(参见 here, Chapter 13 in this PDF。这样您将自动执行参数验证,仅在 ASN.1 架构中定义。GPB 中缺少值/大小限制是一个明显的遗漏。
看看here (overview), here (free schema compiler for C/C++ that looks OK), and here (PDF, reference manual).
ASN.1 的有线格式具有更强的类型(如果您使用 BER 编码)。可以询问有线比特流以找出它包含什么类型的消息。因此,无需像使用 GPB 那样将所有可能的消息包装到一个 oneof
中。