2016-07-07 7 views
2

Ich habe ein Problem mit einer const-Anfrage mit den Google-Protokoll-Puffern mit Grpc. Hier ist mein Problem:Wie mache ich eine direkte Änderung an einem Array mit Grpc und Google-Protokoll-Puffer?

Ich möchte eine In-Place-Änderung eines Array-Wert vornehmen. Dafür habe ich dieses einfache Beispiel geschrieben, in dem ich versuche, ein Array zu übergeben und den gesamten Inhalt zu summieren. Hier ist mein Code:

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

Mein Fehler passiert, wenn ich versuche, das nennen Methode set_values ​​() für das Anfrageobjekt, das als const definiert ist. Ich verstehe, warum dieser Fehler auftritt, aber ich kann einfach keinen Weg finden, um es zu überwinden, ohne eine Kopie des Arrays zu machen.

Ich habe versucht, die Const-Definition zu entfernen, aber die RPC-Aufrufe schlägt fehl, wenn ich das tue.

Da ich neu in dieser RPC-Welt bin und noch mehr über grpc und die Google-Protokoll-Puffer, möchte ich um Ihre Hilfe rufen. Was ist der beste Weg, um dieses Problem zu lösen?

Antwort

0

Bitte sehen Sie meine Antwort here. Der Server erhält eine Kopie des vom Client gesendeten AdderRequest. Wenn Sie es ändern würden, würde das ursprüngliche AdderRequest des Clients nicht geändert werden. Wenn "vor Ort" bedeutet, dass der Server den ursprünglichen Speicher des Clients ändert, kann dies durch keine RPC-Technologie erreicht werden, da der Client und der Server in separaten Adressräumen (Prozessen) ausgeführt werden, selbst auf verschiedenen Computern.

Wenn Sie wirklich den Server benötigen die Client-Speicher zu ändern:

  1. Sicherstellen, dass die Server und Client laufen auf der gleichen Maschine.
  2. Verwenden Sie OS-spezifische shared-memory-APIs, z. B. shm_open() and mmap(), um den gleichen physischen Speicherblock in die Adressräume des Clients und des Servers zu mappen.
  3. Verwenden Sie RPC, um die Kennung (Name) des gemeinsam genutzten Speichers (nicht die tatsächlichen Daten im Speicher) zu übertragen und die Verarbeitung des Servers aufzurufen.
  4. Wenn sowohl der Client als auch der Server den Speicher geöffnet und zugeordnet haben, verfügen beide über Zeiger (wahrscheinlich mit unterschiedlichen Werten in den verschiedenen Adressräumen) gleichen physischen Speicher, so dass der Server lesen kann, was der Client schreibt dort (ohne kopieren oder übertragen) und umgekehrt.
+0

Hallo @asynchronos. Ich glaube, ich habe Ihren Standpunkt verstanden, aber ich denke, ich gebe bereits eine Kopie an den Server (bitte korrigieren Sie mich, wenn ich falsch liege) mit der Zeile 'stub _-> Add (& context, request, & reply);'. Die Sache ist, dass ich versuche, den Wert des Arrays auf der Serverseite mit der Methode set_values ​​() zu ändern, aber da die Signatur der Add-Methode die Anfrage als const macht, kann ich das nicht tun. –

+0

@Eric Warum möchten Sie die Werte des Arrays auf der Serverseite ändern? Möchten Sie das geänderte Array an den Client zurückgeben? Der generierte Code deklariert das AdderRequest-Argument für die Servermethode 'const', weil Änderungen nicht an den Client zurückgemeldet werden. – asynchronos

+0

ja das ist genau was ich will. Senden Sie das Array an den Client zurück und ich möchte keine weitere Kopie erstellen, da mein Array zu groß ist und ich mit einer anderen Kopie wahrscheinlich nicht genügend Speicher habe (10^10 wird die Größe meines Arrays sein) –

Verwandte Themen