如何使用grpc和google协议缓冲区对阵列进行就地修改?

时间:2016-07-07 01:08:18

标签: c++ arrays rpc grpc protocol-buffers

我使用grpc使用谷歌协议缓冲区的const请求有问题。这是我的问题:

我想对数组的值进行就地修改。为此我写了这个简单的例子,我尝试传递一个数组并总结所有内容。这是我的代码:

adder.proto:

syntax = "proto3";

option java_package = "io.grpc.examples";

package adder;

// The greeter service definition.
service Adder {
    // Sends a greeting
    rpc Add (AdderRequest) returns (AdderReply) {}
}

// The request message containing the user's name.
message AdderRequest {
    repeated int32 values = 1;
}

// The response message containing the greetings
message AdderReply {
    int32 sum = 1;
}

server.cc:

//
// Created by Eric Reis on 7/6/16.
//

#include <iostream>
#include <grpc++/grpc++.h>

#include "adder.grpc.pb.h"

class AdderImpl final : public adder::Adder::Service
{
public:
    grpc::Status Add(grpc::ServerContext* context, const adder::AdderRequest* request,
                     adder::AdderReply* reply) override
    {
        int sum = 0;
        for(int i = 0, sz = request->values_size(); i < sz; i++)
        {
            request->set_values(i, 10); // -> this gives an error caused by the const declaration of the request variable
                                        //    error: "Non-const function 'set_values' is called on the const object"
            sum += request->values(i);  // -> this works fine
        }
        reply->set_sum(sum);
        return grpc::Status::OK;
    }
};

void RunServer()
{
    std::string server_address("0.0.0.0:50051");
    AdderImpl service;

    grpc::ServerBuilder builder;
    // Listen on the given address without any authentication mechanism.
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    // Register "service" as the instance through which we'll communicate with
    // clients. In this case it corresponds to an *synchronous* service.
    builder.RegisterService(&service);
    // Finally assemble the server.
    std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
    std::cout << "Server listening on " << server_address << std::endl;

    // Wait for the server to shutdown. Note that some other thread must be
    // responsible for shutting down the server for this call to ever return.
    server->Wait();
}

int main(int argc, char** argv)
{
    RunServer();
    return 0;
}

client.cc:

//
// Created by Eric Reis on 7/6/16.
//

#include <iostream>
#include <grpc++/grpc++.h>

#include "adder.grpc.pb.h"

class AdderClient
{
public:
    AdderClient(std::shared_ptr<grpc::Channel> channel) : stub_(adder::Adder::NewStub(channel)) {}

    int Add(int* values, int sz) {
        // Data we are sending to the server.
        adder::AdderRequest request;
        for (int i = 0; i < sz; i++)
        {
            request.add_values(values[i]);
        }

        // Container for the data we expect from the server.
        adder::AdderReply reply;

        // Context for the client. It could be used to convey extra information to
        // the server and/or tweak certain RPC behaviors.
        grpc::ClientContext context;

        // The actual RPC.
        grpc::Status status = stub_->Add(&context, request, &reply);

        // Act upon its status.
        if (status.ok())
        {
            return reply.sum();
        }
        else {
            std::cout << "RPC failed" << std::endl;
            return -1;
        }
    }

private:
    std::unique_ptr<adder::Adder::Stub> stub_;
};

int main(int argc, char** argv) {
    // Instantiate the client. It requires a channel, out of which the actual RPCs
    // are created. This channel models a connection to an endpoint (in this case,
    // localhost at port 50051). We indicate that the channel isn't authenticated
    // (use of InsecureChannelCredentials()).
    AdderClient adder(grpc::CreateChannel("localhost:50051",
                                          grpc::InsecureChannelCredentials()));
    int values[] = {1,2};
    int sum = adder.Add(values, 2);
    std::cout << "Adder received: " << sum << std::endl;

    return 0;
}

当我尝试在定义为const的请求对象上调用方法set_values()时,会发生错误。我理解为什么会出现这种错误,但我无法找到克服它的方法,而无需复制数组。

我试图删除const定义,但是当我这样做时,RPC调用失败了。

由于我是这个RPC世界的新手,而且更多关于grpc和google协议缓冲区,我想请求你的帮助。解决这个问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

请参阅我的回答here。服务器接收客户端发送的AdderRequest的副本。如果您要修改它,则不会修改客户端的原始AdderRequest。如果通过&#34;到位&#34;你的意思是服务器修改了客户端的原始内存,没有RPC技术可以真正实现这一点,因为客户端和服务器在不同的地址空间(进程)中运行,即使在不同的机器上也是如此。

如果您确实需要服务器来修改客户端的内存:

  1. 确保服务器和客户端在同一台计算机上运行。
  2. 使用特定于操作系统的共享内存API(例如shm_open() and mmap())将同一块物理内存映射到客户端和服务器的地址空间中。
  3. 使用RPC传输共享内存的标识符(名称)(而不是内存中的实际数据)并调用服务器的处理。
  4. 当客户端和服务器都打开并映射内存时,它们都有指针(可能在不同的地址空间中具有不同的值)到相同的物理内存,因此服务器将能够读取客户端在那里写的内容(没有复制或传输),反之亦然。