LoginSignup
1
1

More than 1 year has passed since last update.

ProtocolBuffersとJsonのエンコード/デコード

Posted at

Protocol Buufersのproto3ではJsonフォーマットとの交換が簡単にできます。
プロトコル定義ファイルに記述した型とJsonの型対応に従ってProtocol Buffersにエンコードされ、またその逆のデコードもできます。
(下の例ではgRPCのHelloWorldサンプルに少し手を加えています。)

リソース

Protocol BuffersとJsonの型対応表
https://developers.google.com/protocol-buffers/docs/proto3#json

Protocol Buffersのjson_util関数一覧
https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.util.json_util

環境

$ protoc --version
libprotoc 3.6.1
$ clang++ --version
clang version 10.0.0-4ubuntu1 
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

protoファイル

HelloWorld.proto

syntax = "proto3";

package helloworld;

service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
string name = 1;
}

message HelloReply {
string message = 1;
}

サーバ側コード

server.cxx

#include <iostream>
#include <memory>
#include <string>

#include <grpc++/grpc++.h>

#include "helloworld.grpc.pb.h"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;

class GreeterServiceImpl final : public Greeter::Service {
	Status SayHello(ServerContext* context, const HelloRequest* request,
		HelloReply* reply) override {
		std::string prefix("Hello ");
		reply->set_message(prefix + request->name());
		return Status::OK;
	}
};

void RunServer() {
	std::string server_address("localhost:50051");
	GreeterServiceImpl service;

	ServerBuilder builder;
	
	builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
	
	builder.RegisterService(&service);
	
	std::unique_ptr<Server> server(builder.BuildAndStart());
	std::cout << "Server listening on " << server_address << std::endl;

	server->Wait();
}

int main(int argc, char** argv) {
	RunServer();
	return 0;
}

クライアント側コード

#include <iostream>
#include <memory>
#include <grpc++/grpc++.h>
#include <google/protobuf/util/json_util.h>
#include "helloworld.grpc.pb.h"

using namespace std;
using namespace grpc;

int main(int argc, char ** argv) {
  std::shared_ptr<grpc::Channel> channel = CreateChannel("localhost:50051", InsecureChannelCredentials());
  std::unique_ptr<helloworld::Greeter::Stub> stub = helloworld::Greeter::NewStub(channel);
  ClientContext context;
  helloworld::HelloRequest request;
  helloworld::HelloReply   reply;
  google::protobuf::util::JsonStringToMessage("{\"name\":\"Hello, Hello, Hello, gRPC\"}", &request);
  request.set_name(request.name() + " adding string");
  std::cout << "grpc calling.." << std::endl;
  stub->SayHello(&context, request, &reply);
  std::cout << "grpc called.." << std::endl;
  std::string outstr;
  google::protobuf::util::MessageToJsonString(reply, &outstr);
  std::cout << "decode to json format.:" << outstr.c_str() << ":" << std::endl;

  return 0;
}

Makefile

Makefile

TARG1 = server
SRCS1 = server.cxx helloworld.grpc.pb.cc helloworld.pb.cc
TARG2 = client
SRCS2 = client.cxx helloworld.grpc.pb.cc helloworld.pb.cc
TARG  = $(TARG1) $(TARG2)
LIBS += -pthread -lprotobuf -lgrpc++
FLAGS += -std=c++11 -Wno-unused-parameter -fno-strict-aliasing -fsanitize=address -fno-omit-frame-pointer
LIBDS += -L/usr/lib/llvm-10/lib -L/usr/include/lib

all: $(TARG)

helloworld.pb.cc: helloworld.proto
	protoc -I=. --cpp_out=. ./helloworld.proto
helloworld.grpc.pb.cc: helloworld.proto
	protoc -I=. --grpc_out=. --plugin=protoc-gen-grpc=/usr/bin/grpc_cpp_plugin ./helloworld.proto

$(TARG1): $(SRCS1)
	clang++ $(SRCS1) $(OPTS) $(FLAGS) $(INCS) $(LIBDS) $(LIBS) -o $(TARG1)

$(TARG2): $(SRCS2)
	clang++ $(SRCS2) $(OPTS) $(FLAGS) $(INCS) $(LIBDS) $(LIBS) -o $(TARG2)

実行結果

サーバ側

$ ./server 
Server listening on localhost:50051

クライアント側

$ ./client 
grpc calling..
grpc called..
decode to json format.:{"message":"Hello Hello, Hello, Hello, gRPC adding string"}:
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1