如何使用 grpc 和 google 协议缓冲区对数组进行就地修改?
How do I make an in-place modification on an array using grpc and google protocol buffers?
我在使用 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;
}
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 协议缓冲区更陌生,所以我想寻求您的帮助。解决这个问题的最佳方法是什么?
请看我的回答here。服务器收到客户端发送的 AdderRequest
的副本。如果你要修改它,客户端原来的AdderRequest
不会被修改。如果 "in place" 你的意思是服务器修改了客户端的原始内存,那么没有任何 RPC 技术可以真正做到这一点,因为客户端和服务器 运行 在不同的地址空间(进程)中,甚至在不同的机器上。
如果确实需要服务端修改客户端内存:
- 确保服务器和客户端运行在同一台机器上。
- 使用 OS 特定的共享内存 API,例如 shm_open() and mmap() 将相同的物理内存块映射到客户端和服务器的地址空间。
- 使用RPC传输共享内存的标识符(名称)(不是内存中的实际数据)并调用服务器的处理。
- 当客户端和服务器都打开并映射内存时,它们都有指向相同物理内存的指针(可能在不同的地址空间中具有不同的值),因此服务器将能够读取客户端在那里写入的内容(无需复制或传输),反之亦然。
我在使用 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;
}
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 协议缓冲区更陌生,所以我想寻求您的帮助。解决这个问题的最佳方法是什么?
请看我的回答here。服务器收到客户端发送的 AdderRequest
的副本。如果你要修改它,客户端原来的AdderRequest
不会被修改。如果 "in place" 你的意思是服务器修改了客户端的原始内存,那么没有任何 RPC 技术可以真正做到这一点,因为客户端和服务器 运行 在不同的地址空间(进程)中,甚至在不同的机器上。
如果确实需要服务端修改客户端内存:
- 确保服务器和客户端运行在同一台机器上。
- 使用 OS 特定的共享内存 API,例如 shm_open() and mmap() 将相同的物理内存块映射到客户端和服务器的地址空间。
- 使用RPC传输共享内存的标识符(名称)(不是内存中的实际数据)并调用服务器的处理。
- 当客户端和服务器都打开并映射内存时,它们都有指向相同物理内存的指针(可能在不同的地址空间中具有不同的值),因此服务器将能够读取客户端在那里写入的内容(无需复制或传输),反之亦然。