Protocol Buffers
Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
Category
Why Use Protocol Buffers
우리가 사용하려고 하는 예제는 사람들의 주소 정보를 파일로 쓰거나 읽어오는 매우 간단한 address book 어플리케이션이다. 주소록에 있는 각각의 사람들은 이름, ID, 이메일 주소, 전화번호를 가지고 있다. 그러면 이와 같은 구조화된 데이터를 어떻게 직렬화하고 데이터를 얻어올 것인가? 이를 풀 수 있는 방법이 몇 가지 있다.
- 메모리의 raw 데이터들은 바이너리 형태로 저장되거나 보내질 수 있다. 시간이 지나면서, 이러한 형태는 받거나 읽는 코드가 정확히 동일한 메모리 레이아웃으로 컴파일되어야 하기 때문에 깨지기 쉬운 형태가 된다. 그리고, raw 포맷으로 데이터가 축적된 파일들과 그러한 포맷으로 연결된 어플리케이션들이 퍼지게 되면, 데이터 포맷을 확장하는 것은 매우 어려운 일이 된다.
- 애드훅 형태로 데이터를 단일 스트링으로 인코딩하는 것을 사용할 수 있다("12:3-23:67" 처럼 4개의 정수로 인코딩된 형태처럼). 이러한 형태는 간단하고 확장이 용이하지만, 인코딩과 파싱하는 코드를 작성해야 하고, 파싱은 약간의 런타임 비용을 부과한다. 매우 간단한 데이터를 인코딩하는데는 이 방법이 최선이다.
- XML로 데이터를 직렬화하는 방법. 이 방법은 매우 매력적인 방법이다. 왜냐하면, XML은 가독성이 높고 많은 언어들로 바인딩된 라이브러리들이 있다. 다른 어플리케이션이나 프로젝트와 데이터를 공유하려면 이 방법은 좋은 선택이 될 수 있다. 하지만, XML은 공간 집약적이고 어플리케이션에서 많은 퍼포먼스 패널티를 가져오는 인코딩과 디코딩으로 악명이 자자하다. 그리고 XML DOM 트리를 탐색하는 것은 클래스에서 일반적으로 필드들을 탐색하는 것 보다 복잡하다.
프로토콜 버퍼는 이러한 문제점들을 해결할 수 있는 유연하고, 효율적이고 자동화된 솔루션이다. 프로토콜 버퍼로, 저장하려고 하는 데이터 구조에 대한 .proto 파일을 작성한다. 그 파일로부터, 프로토콜 버퍼 컴파일러는 효율적인 바이너리 포맷의 프로토콜 버퍼 데이터를 자동으로 인코딩하고 파싱하는 것을 구현하는 클래스를 생성한다. 생성된 클래스는 프로토콜 버퍼로 만들어진 필드들에 대한 getter와 setter를 제공하고 하나의 유닛으로서 프로토콜 버퍼를 읽거나 쓰는 디테일한 부분을 책임진다. 더욱 중요한 것은, 프로토콜 버퍼 포맷은 이전 포맷으로 인코딩된 데이터를 여전히 읽을 수 있게 하면서 포맷을 확장하는 방법을 지원한다.
How to install
Define syntax
변수의 정의는 아래와 같이 입력한다.
한정자 (Qualifier)
required
이 필드의 값은 반드시 제공되어야 한다. 그렇지 않으면 메시지는 초기화 되지 않은 것으로 간주될 것이다. libprotobuf가 디버그 모드에서 컴파일되면, 초기화되지 않은 메시지를 직렬화하는 것은 실패를 유발할 것이다. 최적화 빌드에서는, 이러한 체크가 스킵되고 메시지는 그냥 작성될 것이다. 하지만, 초기화되지 않은 메시지를 파싱하는 것은 항상 실패할 것이다(파싱 매소드에서 false를 리턴함으로서). 이 외에는, required 필드는 정확히 optional 필드처럼 행동한다.
optional
이 필드는 셋팅되도 되고 안되도 된다. 이 필드가 셋팅되지 않으면, 기본값이 사용된다. 간단한 타입들에게는, 우리가 위의 예제에서 전화번호 type에서 했던 것처럼, 제작자가 자신의 기본값을 지정해 줄 수 있다. 그렇지 않으면, 시스템의 기본값이 사용된다.: 숫자 타입에 대해서는 0, 스트링 타입에는 빈 스트링이, bool에는 false가 사용된다. 임베디드된 메시지들에 대해서는 기본값은 항상 필드에 셋팅된 값이 없다는 메시지의 "default instance"이거나 "prototype"이다. 명시적으로 값이 셋팅되지 않은 optional(이나 required) 필드의 값을 가져오는 접근자를 호출하는 것은 항상 그 필드의 기본값을 리턴한다.
repeated
이 필드는 여러번 반복될 것이다(0번을 포함해서). 반복되는 값들의 순서는 프로토콜 버퍼에 보존될 것이다. 반복적인 필드들은 다이나믹하게 사이즈가 변하는 배열들로 생각할 수 있을 것이다.
Example
message Contents {
required string name = 1;
optional int32 file_size = 2 [default = 0];
optional int32 remark = 3;
enum ContentsType {
MOVIE = 0;
TEXT = 1;
IMAGE = 2;
MUSIC = 3;
}
optional ContentsType type = 4 [default = TEXT];
}
Troubleshooting
Python import error
Python에서 아래와 같은 에러가 발생할 수 있다.
이 경우 아래와 같이 Python용 Protobuf 패키지를 설치하면 된다.
Couldn't build proto file into descriptor pool: duplicate file name
../../../.pyenv/versions/opy-your-3.9.11/lib/python3.9/site-packages/proj/proto/daemon/daemon_api_pb2.py:19: in <module>
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'...')
E TypeError: Couldn't build proto file into descriptor pool: duplicate file name (daemon_api.proto)
동일한 이름의 .proto
가 빌드되었다. 찾아서 중복을 제거하자.
Local Download
- Protocol Buffers v3.0.0-beta-2
-
Protobuf-3.0.0-beta-2.tar.gz
- Protocol Buffers v3.2.0 (2017-02-08)
-
Protobuf-3.2.0.tar.gz
See also
Favorite site
Documentation
What is ProtoBuf
- Protocol Buffer를 파헤쳐보자: Google의 Protocol Buffer 1부
- Protocol Buffer를 파헤쳐보자: Google의 Protocol Buffer 2부
- 직렬화 방법, 구글의 Protocol Buffers
- GPGStudy: 센스있게 바이너리 저장하는 노하우 비법 공개점
Guide
- Google Protocol Buffers 기본 사용법
- 구글 프로토콜 버퍼 (Google Protocl Buffer) 1
- [추천] Protocol Buffer Basics: C++ 2
- Protocol Buffers를 패킷으로 활용해 보자