프로토콜 버퍼

**프로토콜 버퍼**(**Protocol Buffers**, **Protobuf**)는 구조화된 데이터를 직렬화하는 데 사용되는 자유-오픈 소스 크로스 플랫폼 데이터 형식이다. 이는 네트워크를 통해 서로 통신하는 프로그램을 개발하거나 데이터를 저장하는 데 유용하다. 이 방법은 데이터의 구조를 설명하는 인터페이스 정의 언어와, 해당 설명으로부터 구조화된 데이터를 나타내는 바이트 스트림을 생성하거나 구문 분석하기 위한 소스 코드를 생성하는 프로그램으로 구성된다.

## 개요
구글은 내부 사용을 위해 프로토콜 버퍼를 개발했으며, 여러 언어를 위한 코드 생성기를 오픈 소스 라이선스로 제공했다.

프로토콜 버퍼의 설계 목표는 단순성과 성능을 강조했다. 특히 XML보다 작고 빠르게 설계되었다.

프로토콜 버퍼는 구글 내에서 모든 종류의 구조화된 정보를 저장하고 교환하는 데 널리 사용된다. 이 방법은 구글의 거의 모든 서버 간 통신에 사용되는 맞춤형 원격 프로시저 호출(RPC) 시스템의 기초 역할을 한다.

프로토콜 버퍼는 아파치 스리프트, 아마존 Ion, 마이크로소프트 Bond 프로토콜과 유사하며, gRPC라고 불리는 정의된 서비스를 위해 사용할 구체적인 RPC 프로토콜 스택을 제공한다.

데이터 구조 스키마(메시지라고 함)와 서비스는 proto 정의 파일(`.proto`)에 기술되고 `protoc`로 컴파일된다. 이 컴파일은 이러한 데이터 구조의 송신자나 수신자가 호출할 수 있는 코드를 생성한다. 예를 들어, `example.proto`로부터 `example.pb.cc`와 `example.pb.h`가 생성된다. 이 파일들은 `example.proto`에 정의된 각 메시지와 서비스에 대한 C++ 클래스를 정의한다.

표준적으로 메시지는 작고 상위 및 하위 호환성이 있는 이진 전송 형식으로 직렬화되지만, 자기 서술적(self-describing)이지는 않다(즉, 외부 사양 없이는 필드의 이름, 의미 또는 전체 데이터 타입을 알 수 있는 방법이 없다). 프로토콜 버퍼 파일 내에 이러한 외부 사양(스키마)을 포함하거나 참조하는 정의된 방법은 없다. 공식적으로 지원되는 구현에는 ASCII 직렬화 형식이 포함되지만, 이 형식은 자기 서술적이긴 하나 상위 및 하위 호환성 동작을 상실하므로 사람이 편집하거나 디버깅하는 용도 외의 애플리케이션에는 좋은 선택이 아니다.

프로토콜 버퍼의 주요 목적은 네트워크 통신을 원활하게 하는 것이지만, 그 단순성과 속도 덕분에 특히 향후 다른 언어나 시스템과의 상호 운용성이 필요할 수 있는 경우 데이터 중심 C++ 클래스 및 구조체의 대안이 되기도 한다.

## 제한 사항
프로토콜 버퍼는 단일 사양이 없다. 이 형식은 몇 메가바이트를 초과하지 않고 메모리에 즉시 로드/전송할 수 있는 작은 데이터 청크에 가장 적합하며, 따라서 스트리밍 가능한 형식은 아니다. 라이브러리는 기본적으로 압축을 제공하지 않는다. 또한 비객체 지향 언어(예: 포트란)에서는 이 형식이 잘 지원되지 않는다.

## 예제
프로토콜 버퍼를 특정 용도로 사용하기 위한 스키마는 정수를 사용하여 각 필드를 식별하며, 데이터 유형을 필드 이름과 연결한다. (프로토콜 버퍼 데이터에는 필드 이름이 아닌 숫자만 포함되어 있어, 데이터에 필드 이름을 포함하는 시스템에 비해 대역폭/저장 공간을 절약할 수 있다.)

```protobuf
// polyline.proto
syntax = "proto2";

message Point {
  required int32 x = 1;
  required int32 y = 2;
  optional string label = 3;
}

message Line {
  required Point start = 1;
  required Point end = 2;
  optional string label = 3;
}

message Polyline {
  repeated Point point = 1;
  optional string label = 2;
}
```


"Point" 메시지는 필수 데이터 항목인 x와 y를 정의한다. 데이터 항목 label은 선택 사항이다. 각 데이터 항목에는 태그가 있다. 태그는 등호 다음에 정의된다. 예를 들어, x는 태그 1을 갖는다.

둘 다 Point를 사용하는 "Line" 및 "Polyline" 메시지는 프로토콜 버퍼에서 구성(composition)이 작동하는 방식을 보여준다. Polyline에는 repeated 필드가 있으므로 Polyline은 (정해지지 않은 수의) 점들의 집합처럼 동작한다.

이 스키마는 이후 하나 이상의 프로그래밍 언어에서 사용하기 위해 컴파일될 수 있다. 구글은 C++, 자바 또는 파이썬용 출력을 생성할 수 있는 `protoc`라는 컴파일러를 제공한다. 20개 이상의 다른 언어에 대해 언어 종속적인 출력을 생성하기 위해 다른 소스에서 제공하는 스키마 컴파일러들도 사용할 수 있다.

예를 들어, 위의 프로토콜 버퍼 스키마의 C++ 버전이 생성된 후, C++ 소스 코드 파일인 polyline.cpp는 다음과 같이 메시지 객체를 사용할 수 있다.

```cpp
// polyline.cpp
#include "polyline.pb.h"  // "protoc polyline.proto" 호출로 생성됨

Line* createNewLine(const std::string& name) {
  // (10, 20)에서 (30, 40)까지의 선 생성
  Line* line = new Line;
  line->mutable_start()->set_x(10);
  line->mutable_start()->set_y(20);
  line->mutable_end()->set_x(30);
  line->mutable_end()->set_y(40);
  line->set_label(name);
  return line;
}

Polyline* createNewPolyline() {
  // (10,10) 및 (20,20)에 점이 있는 폴리라인 생성
  Polyline* polyline = new Polyline;
  Point* point1 = polyline->add_point();
  point1->set_x(10);
  point1->set_y(10);
  Point* point2 = polyline->add_point();
  point2->set_x(20);
  point2->set_y(20);
  return polyline;
}
```


## 지원 언어
Protobuf 2.0은 C++, 자바, C 샤프, 및 파이썬을 위한 코드 생성기를 제공한다.

Protobuf 3.0은 C++, 자바(저사양 환경을 위한 변형인 JavaNano 포함), 코틀린, 파이썬, Go, 루비, 오브젝티브-C, C 샤프, PHP, 다트를 위한 코드 생성기를 제공한다. 또한 3.0.0-beta-2부터 자바스크립트를 지원한다.

서드 파티 구현은 에이다, Ballerina, C, C++, 다트, Elixir, 얼랭, 하스켈, 자바스크립트, 줄리아, 님, 펄, PHP, 프롤로그, R, 러스트, 스칼라, 및 스위프트에 대해서도 사용 가능하다.

## 같이 보기
* GRPC
* ASN.1

## 각주

## 외부 링크
*  Official documentation at developers.google.com
*  Official project page at Github project hosting

분류:데이터 직렬화 포맷
분류:구글의 소프트웨어