Google Protocol Buffers 소개
Binary Protocol인 Google Protocol Buffers에 대해 알아보자
1. Google Protocol Buffers 소개
Protocol Buffers는 구글에서 만든 것으로 언어 중립적, 플랫폼 중립적이면서 통신 프로토콜, 데이터 저장 또는 다른 곳에서 사용을 위한 구조화된 데이터 직렬화의 확장성 있는 방법입니다.
(Protocol buffers are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more.)
Protocol Buffers는 바이너리 프로토콜로 XML이나 JSON 처럼 사람이 직접 보고 분석할 수 없는 메모리 기반의 자료 구조를 말한다. 이런 바이너리 프로토콜은 데이터를 전달할 때 특정 포맷으로 변환할 필요가 없고, 데이터 수신시 파싱이 필요 없기 때문에 속도가 텍스트 프로토콜(XML, JSON 또는 HTTP 등)에 비해 상당히 빠르다는 장점이 있다.
Protocol Buffers을 사용하기 위해서는 Protocol Buffer Language을 사용하여 필드들을 정의하여 데이터를 구조화 후 컴파일을 통해 개발에 필요한 언어 코드을 자동 생성한다. 여기서 '구조화'라는 의미는 각 필드의 데이터들을 크기 또는 데이터 타입으로 정의하는 것을 의미하며, XML 스키마 파일을 만드는 것과 유사하다.
Protocol Buffer Language 컴파일러는 모두 C++로 구현되어 있기 때문에 GitHub에서 다운로드 받아 빌드할 수 있으며, 이미 빌드된 바이너리 파일을 다운로드 받아 사용할 수 있다.(https://github.com/google/protobuf/releases)
데이터를 구조화 하기 위해서는 Protocol Buffer Language을 사용한다. 현재 Protocol Buffer Language는 proto2와 proto3 두 버전이 공개 되어 있다. 자세한 내용은 아래 링크를 참고.
아래 예저는 Proto3로 정의된 구조화 데이터 선언이다.
두 버전에서 주요 차이점은 적색으로 표시한 것으로, Proto3에서는 required와 optional은 사용할 수 없으며, 현재 Protocol Buffer Language 버전을 명시해야 한다.
그리고 아래 'query' 필드처럼 필드 이름 뒤에 ' = 숫자'는 부여된 고유 번호로 해당 영역( '{'와 '}'로 정의) 에서는 고유하게 유지되어야 한다.
다시 말하면 아래와 같이 각 영역에서(색상으로 표시) 고유하게 부여되어야 한다.
Protocol Buffers는 바이너리 프로토콜로 XML이나 JSON 처럼 사람이 직접 보고 분석할 수 없는 메모리 기반의 자료 구조를 말한다. 이런 바이너리 프로토콜은 데이터를 전달할 때 특정 포맷으로 변환할 필요가 없고, 데이터 수신시 파싱이 필요 없기 때문에 속도가 텍스트 프로토콜(XML, JSON 또는 HTTP 등)에 비해 상당히 빠르다는 장점이 있다.
Protocol Buffers을 사용하기 위해서는 Protocol Buffer Language을 사용하여 필드들을 정의하여 데이터를 구조화 후 컴파일을 통해 개발에 필요한 언어 코드을 자동 생성한다. 여기서 '구조화'라는 의미는 각 필드의 데이터들을 크기 또는 데이터 타입으로 정의하는 것을 의미하며, XML 스키마 파일을 만드는 것과 유사하다.
Protocol Buffer Language 컴파일러는 모두 C++로 구현되어 있기 때문에 GitHub에서 다운로드 받아 빌드할 수 있으며, 이미 빌드된 바이너리 파일을 다운로드 받아 사용할 수 있다.(https://github.com/google/protobuf/releases)
2. Protocol Buffer Language
Google의 Protocol Buffers 소스는 GitHub에 공개되어 있다. 현재 C++, Java, Python, Objective-C, C#, JavaNano, JavaScript, Ruby, Go, PHP을 지원한다.데이터를 구조화 하기 위해서는 Protocol Buffer Language을 사용한다. 현재 Protocol Buffer Language는 proto2와 proto3 두 버전이 공개 되어 있다. 자세한 내용은 아래 링크를 참고.
- Proto2 언어 가이드: https://developers.google.com/protocol-buffers/docs/proto
- Proto3 언어 가이드: https://developers.google.com/protocol-buffers/docs/proto3
2.1 Proto2와 Proto3의 기본적인 차이점
다음은 Proto2로 정의된 구조화 데이터 선언이다.
message SearchRequest { required string query = 1; optional int32 page_number = 2; optional int32 result_per_page = 3; }
아래 예저는 Proto3로 정의된 구조화 데이터 선언이다.
syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
두 버전에서 주요 차이점은 적색으로 표시한 것으로, Proto3에서는 required와 optional은 사용할 수 없으며, 현재 Protocol Buffer Language 버전을 명시해야 한다.
그리고 아래 'query' 필드처럼 필드 이름 뒤에 ' = 숫자'는 부여된 고유 번호로 해당 영역( '{'와 '}'로 정의) 에서는 고유하게 유지되어야 한다.
string query = 1;
다시 말하면 아래와 같이 각 영역에서(색상으로 표시) 고유하게 부여되어야 한다.
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4; }
2.2 Proto3 버전으로 데이터 구조화 및 언어별 코드 생성하기
SearchRequest.proto 파일 이름으로 아래와 같이 파일을 작성한다.SearchRequest.proto
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
그리고 Protocol Buffer Language 컴파일러을 사용하여 코드를 자동으로 생성한다. 이 예제는 macOS에서 테스트 하였으며, Protocol Buffer Language 컴파일러 버전은 3.1.0을 사용한다. 그리고 우리가 사용할 옵션들을 빨강색으로 표시했다.
$ ../bin/protoc --version
libprotoc 3.1.0
$ ../bin/protoc --help
Usage: ../bin/protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:
-IPATH, --proto_path=PATH Specify the directory in which to search for
imports. May be specified multiple times;
directories will be searched in order. If not
given, the current working directory is used.
--version Show version info and exit.
-h, --help Show this text and exit.
--encode=MESSAGE_TYPE Read a text-format message of the given type
from standard input and write it in binary
to standard output. The message type must
be defined in PROTO_FILES or their imports.
--decode=MESSAGE_TYPE Read a binary message of the given type from
standard input and write it in text format
to standard output. The message type must
be defined in PROTO_FILES or their imports.
--decode_raw Read an arbitrary protocol message from
standard input and write the raw tag/value
pairs in text format to standard output. No
PROTO_FILES should be given when using this
flag.
-oFILE, Writes a FileDescriptorSet (a protocol buffer,
--descriptor_set_out=FILE defined in descriptor.proto) containing all of
the input files to FILE.
--include_imports When using --descriptor_set_out, also include
all dependencies of the input files in the
set, so that the set is self-contained.
--include_source_info When using --descriptor_set_out, do not strip
SourceCodeInfo from the FileDescriptorProto.
This results in vastly larger descriptors that
include information about the original
location of each decl in the source file as
well as surrounding comments.
--dependency_out=FILE Write a dependency output file in the format
expected by make. This writes the transitive
set of input file paths to FILE
--error_format=FORMAT Set the format in which to print errors.
FORMAT may be 'gcc' (the default) or 'msvs'
(Microsoft Visual Studio format).
--print_free_field_numbers Print the free field numbers of the messages
defined in the given proto files. Groups share
the same field number space with the parent
message. Extension ranges are counted as
occupied fields numbers.
--plugin=EXECUTABLE Specifies a plugin executable to use.
Normally, protoc searches the PATH for
plugins, but you may specify additional
executables not in the path using this flag.
Additionally, EXECUTABLE may be of the form
NAME=PATH, in which case the given plugin name
is mapped to the given executable even if
the executable's own name differs.
--cpp_out=OUT_DIR Generate C++ header and source.
--csharp_out=OUT_DIR Generate C# source file.
--java_out=OUT_DIR Generate Java source file.
--javanano_out=OUT_DIR Generate Java Nano source file.
--js_out=OUT_DIR Generate JavaScript source.
--objc_out=OUT_DIR Generate Objective C header and source.
--php_out=OUT_DIR Generate PHP source file.
--python_out=OUT_DIR Generate Python source file.
--ruby_out=OUT_DIR Generate Ruby source file.
아래와 같이 자동 생성 파일의 옵션을 C++, Java, JavaScript, Python으로 한번에 정의할 수도 있고,
$ ../bin/protoc --cpp_out=./output/cpp/ --java_out=./output/java/ --js_out=./output/js/ --python_out=./output/python/ SearchRequest.proto
특정 언어만 설정할 수 있다.
$ ../bin/protoc --js_out=./output/js/ SearchRequest.proto
Javascript와 C++로 자동 생성된 코드는 각각 다음과 같다.
[Javascript]
[Python]
C++ 코드는 너무 길고 복잡해 보여 아래 링크만 적어 둔다.
[Javascript]
[Python]
C++ 코드는 너무 길고 복잡해 보여 아래 링크만 적어 둔다.
- SearchRequest.pb.h: https://gist.github.com/kmansoo/b2d74a76e7131e7618a82a6570e4c09c
- SearchRequest.pb.cc: https://gist.github.com/kmansoo/616d3e0ec7b45e52c707220823a93ede
3. Reference
1. Google Protocol Buffers: https://developers.google.com/protocol-buffers/
2. Source Code, GitHub: https://github.com/google/protobuf
댓글
댓글 쓰기