doctopus
doctopus

Reputation: 5647

How to send byte data over gRPC with C/C++?

So I'm using gRPC to store data in a key-value store.

The protos look like this:

syntax = "proto3";

package keyvaluestore;

service KeyValueStore {
  rpc AddUser(Credentials) returns (Response) {}
  rpc Get(Request) returns (Response) {}
  rpc Put(Request) returns (Response) {}
  rpc Cput(Request) returns (Response) {}
  rpc Delete(Request) returns (Response) {}
}

message Credentials {
  string user = 1;
  string passwd = 2;
}

message Request {
  string user = 1;
  string key = 2;
  bytes val = 3;
  bytes val2 = 4;
  string addr = 5;
  string command = 6;
}

message Response {
  bytes val = 1;
  uint32 nbytes = 2;
  string message = 3;
}

Right now, the issue is that if we send over say, an image as byte data which can include the null byte, then when the server receives it in the Request object, it treats it as a string; when it does this it only reads it up the the first null byte.

How we pack the Request object on the client side:

bool KeyValueStoreClient::Put(const string& user, const string& key, const char* val) {
  Request req;
  req.set_user(user);
  req.set_key(key);
  req.set_val(val);

  ClientContext ctx;
  Response res;
  Status status = stub_->Put(&ctx, req, &res);
}

Server receives req->val() as a string instead of char*:

Status KeyValueStoreServiceImpl::Put(ServerContext* ctx, const Request* req, Response* res) {
  // req->val() is a string

}

Upvotes: 2

Views: 2949

Answers (1)

davidbak
davidbak

Reputation: 5999

In your method Put the val argument is a const char*, not a std::string.

Protobuf documentation for C++ generated code (i.e., the interface to your messages) says that when setting a value using a const char* (the void set_foo(const char* value) overload) it uses the first \0 as a terminator.

Tell it the size explicitly by using the void set_foo(const char* value, int size) overload.

Upvotes: 3

Related Questions