C++ 如何使用grpc和google协议缓冲区对阵列进行就地修改?
我对使用grpc的google协议缓冲区的const请求有问题。我的问题是: 我想对数组的值进行就地修改。为此,我编写了一个简单的示例,其中我尝试传递一个数组并对其所有内容求和。这是我的密码: adder.proto: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
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;
}