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

C++ 如何使用grpc和google协议缓冲区对阵列进行就地修改?,c++,arrays,rpc,grpc,protocol-buffers,C++,Arrays,Rpc,Grpc,Protocol Buffers,我对使用grpc的google协议缓冲区的const请求有问题。我的问题是: 我想对数组的值进行就地修改。为此,我编写了一个简单的示例,其中我尝试传递一个数组并对其所有内容求和。这是我的密码: adder.proto: syntax = "proto3"; option java_package = "io.grpc.examples"; package adder; // The greeter service definition. service Adder { // Sen

我对使用grpc的google协议缓冲区的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;
}
//
//由Eric Reis于2016年7月6日创建。
//
#包括
#包括
#包括“adder.grpc.pb.h”
AdderImpl final类:公共加法器::加法器::服务
{
公众:
grpc::Status Add(grpc::ServerContext*上下文,常量加法器::AdderRequest*请求,
加法器::加法器执行*应答)覆盖
{
整数和=0;
对于(inti=0,sz=request->values_size();iset_values(i,10);//->这会给出由request变量的const声明引起的错误
//错误:“对常量对象调用了非常量函数“set_values”
sum+=request->values(i);//->这很好
}
回复->设置总和(总和);
返回grpc::Status::OK;
}
};
void RunServer()
{
std::字符串服务器地址(“0.0.0.0:50051”);
ADERIMPL服务;
grpc::ServerBuilder;
//在没有任何身份验证机制的情况下侦听给定地址。
addListengPort(服务器地址,grpc::unsecureServerCredentials());
//将“服务”注册为我们将通过其进行通信的实例
//在本例中,它对应于一个*同步*服务。
注册服务(和服务);
//最后组装服务器。
std::unique_ptr服务器(builder.BuildAndStart());
std::cout请查看我的答案。服务器收到客户端发送的
AdderRequest
副本。如果要修改它,客户端的原始
AdderRequest
将不会被修改。如果通过“就地”您的意思是服务器修改客户机的原始内存,没有任何RPC技术能够真正做到这一点,因为客户机和服务器在单独的地址空间(进程)中运行,即使在不同的机器上也是如此

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

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

  • Hi@asynchronos。我想我理解了你的观点,但我想我已经在向服务器传递一个副本(如果我错了,请纠正我),行
    stub\uux->Add(&context,request,&reply);
    。问题是我正在尝试用set\u values()方法修改服务器端数组的值,但由于Add方法的签名使请求成为常量,我无法这样做。@Eric为什么要在服务器端修改数组的值?您是否打算将修改后的数组传回客户端?生成的代码向服务器方法声明AdderRequest参数
    const
    ,因为e任何更改都不会传回客户端。是的,这正是我想要的。将阵列发送回客户端,我不想再制作一个副本,因为我的阵列太大,使用另一个副本可能会耗尽内存(10^10将是我阵列的大小)在服务器上,您可以尝试丢弃AdderRequest的
    常量,但在修改数组后,它不会自动发送回客户端。您需要在AdderRequest中使用该数组。我不知道gRPC是否会让您从AdderRequest中获取数组引用并将其放入AdderRequest中。即使在您从服务器方法返回后,gRPC将希望序列化整个回复,并通过套接字将其传输到客户端。客户端在其回复中接收的数组将不同于其请求中的数组,并且两者都不同于服务器中接收的请求中的数组。因此,我认为您将有3个这样的数组同时,考虑使用OS的共享内存能力来精确地共享一个数组。
    
    //
    // 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;
    }