2016-07-07 2 views
2

У меня возникла проблема с запросом const с буферами протокола google, использующими grpc. Вот моя проблема:Как создать модификацию на месте массива с использованием буферов протокола grpc и google?

Я хотел бы сделать внутреннюю модификацию значения массива. Для этого я написал этот простой пример, где я пытаюсь передать массив и суммировать все его содержимое. Вот мой код:

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; 
} 

Моя ошибка происходит, когда я пытаюсь вызвать метод set_values ​​() объекта запроса, который определяется как const. Я понимаю, почему эта ошибка возникает, но я просто не могу понять, как ее преодолеть, не делая копию массива.

Я попытался удалить определение const, но вызовы RPC терпят неудачу, когда я это делаю.

Поскольку я новичок в этом мире RPC и даже больше на grpc и буферах протокола google, я бы хотел обратиться за помощью. Каков наилучший способ решить эту проблему?

ответ

0

См. Мой ответ here. Сервер получает копию отправленного клиентом AdderRequest. Если вы хотите изменить его, исходный код AdderRequest10 не будет изменен. Если «на месте» означает, что сервер изменяет исходную память клиента, никакая технология RPC не может действительно этого добиться, поскольку клиент и сервер работают в отдельных адресных пространствах (процессах) даже на разных машинах.

Если вы действительно нужен сервер изменения в памяти клиента:

  1. Убедитесь, что сервер и клиент работать на той же машине.
  2. Используйте OS-специфичные интерфейсы общей памяти, такие как shm_open() and mmap(), чтобы отобразить один и тот же фрагмент физической памяти в адресные пространства как клиента, так и сервера.
  3. Используйте RPC для передачи идентификатора (имя) общей памяти (а не фактических данных в памяти) и для вызова обработки сервера.
  4. Когда оба клиента и сервер открыли и сопоставили память, оба они имеют указатели (вероятно, с разными значениями в разных адресных пространствах) на то же физической памяти, поэтому сервер сможет читать то, что пишет клиент там (без копирования или передачи) и наоборот.
+0

Hi @asynchronos. Я думаю, что я понял вашу мысль, но я думаю, что я уже передаю копию на сервер (пожалуйста, исправьте меня, если я ошибаюсь) с линией 'stub _-> Add (& context, request, & reply);'. Дело в том, что я пытаюсь изменить значение массива на стороне сервера с помощью метода set_values ​​(), но поскольку подпись метода Add делает запрос const, я не могу этого сделать. –

+0

@Eric Почему вы хотите изменить значения массива на стороне сервера? Это ваше намерение передать измененный массив обратно клиенту? Сгенерированный код объявляет аргумент AdderRequest методу сервера 'const', потому что любые изменения не будут переданы клиенту обратно. – asynchronos

+0

да, это именно то, что я хочу. Отправляйте массив клиенту, и я не хотел бы делать другую копию, потому что мой массив слишком большой, а с другой копией у меня, вероятно, закончится нехватка памяти (10^10 будет размером моего массива) –