如何使用GRPC发送protobuf :: DynamicMessage?

时间:2017-04-08 07:28:15

标签: protocol-buffers grpc

我最近一直在玩GRPCProtocol Buffers,以便熟悉C ++中的两个框架。

我想尝试一下反射功能,所以我设置了一个非常简单的服务,其中(支持反射的)服务器公开了以下接口文件:

syntax = "proto3";

package helloworld;

service Server {
  rpc Add (AddRequest) returns (AddReply) {}
}

message AddRequest {
  int32 arg1 = 1;
  int32 arg2 = 2;
}

message AddReply {
  int32 sum = 1;
}

在客户端,由于grpc::ProtoReflectionDescriptorDatabase,我可以看到上一个方法。因此,我可以通过DynamicMessageFactory创建消息。但是,我还没有能够将消息实际发送到服务器,也没有找到文档中的任何具体细节。也许它太明显了,我完全迷失了......

任何提示都将深表感谢!

using namespace google::protobuf;

void demo()
{
    std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());

    //  Inspect exposed method

    grpc::ProtoReflectionDescriptorDatabase reflection_database(channel);

    std::vector<std::string> output;

    reflection_database.GetServices(&output);

    DescriptorPool reflection_database_pool(&reflection_database);

    const ServiceDescriptor* service = reflection_database_pool.FindServiceByName(output[0]);

    const MethodDescriptor* method = service->method(0);

    //  Create request message

    const Descriptor* input_descriptor = method->input_type();

    FileDescriptorProto input_proto;

    input_descriptor->file()->CopyTo(&input_proto);

    DescriptorPool pool;

    const FileDescriptor* input_file_descriptor = pool.BuildFile(input_proto);

    const Descriptor* input_message_descriptor = input_file_descriptor->FindMessageTypeByName(input_descriptor->name());

    DynamicMessageFactory factory;

    Message* request = factory.GetPrototype(input_message_descriptor)->New();

    //  Fill request message (sum 1 plus 2)

    const Reflection* reflection = request->GetReflection();

    const FieldDescriptor* field1 = input_descriptor->field(0);

    reflection->SetInt32(request, field1, 1);

    const FieldDescriptor* field2 = input_descriptor->field(1);

    reflection->SetInt32(request, field2, 2);

    //  Create response message

    const Descriptor* output_descriptor = method->output_type();

    FileDescriptorProto output_proto;

    output_descriptor->file()->CopyTo(&output_proto);

    const FileDescriptor* output_file_descriptor = pool.BuildFile(output_proto);

    const Descriptor* output_message_descriptor = output_file_descriptor->FindMessageTypeByName(output_descriptor->name());

    Message* response = factory.GetPrototype(output_message_descriptor)->New();

    //  How to create a call...?

    // ...is grpc::BlockingUnaryCall the way to proceed?
}

1 个答案:

答案 0 :(得分:0)

已经有几年了,但是由于您没有得到答案,所以我会尝试。您也没有使用特定语言标记问题,但看起来您正在使用CPP。我无法为CPP提供解决方案,但可以为JVM语言提供解决方案。

首先,以下内容摘自我正在开发的名为okgrpc的开源库。这是用Java创建动态gRPC客户端/ CLI的第一次尝试。

以下是使用DynamicMessage拨打电话的一般步骤:

  1. 使用gRPC反射获取要调用的服务的所有DescriptorProtos.FileDescriptorProto
  2. 为该服务中的所有类型和方法创建索引。
  3. 找到与您要调用的方法相对应的Descriptors.MethodDescriptor
  4. 将您的输入转换为DynamicMessage。当然,如何执行此操作取决于输入。如果是JSON字符串,则可以使用JsonFormat类。
  5. 使用方法名称,类型(一元等),请求和响应编组器构建io.grpc.MethodDescriptor。您需要编写自己的DynamicMessage编组器。
  6. 使用ClientCalls API执行RPC。

显然,细节决定成败。如果使用Java,则可以使用我的库,让它成为我的问题。如果使用其他语言,祝您好运。