일기

Protocol Buffers

Realuda72 2025. 1. 7. 23:01

 프로젝트를 진행하는데, node.js 서버와 unity 클라이언트 간에 tcp 통신을 할 필요가 생겼다.

 js와 c#간에 패킷을 통신을 하는데 어려움을 겪은 적이 있기 때문에, protocol buffers라는걸 알아보기로 했다.

 

https://protobuf.dev/

 

Protocol Buffers

Protocol Buffers are language-neutral, platform-neutral extensible mechanisms for serializing structured data.

protobuf.dev

 

Protocol Buffers가 무엇인가

 Protocol Buffers are language-neutral, platform-neutral extensible mechanisms for serializing structured data.

 Protocol Buffers 페이지를 가면 제일 먼저 있는 문장이다. 언어가 상관없고, 플랫폼도 상관없는 확장 가능한 구조적 데이터 시리얼라이징 메커니즘이라고 한다.

 문장 뒤쪽은 사실 무슨 뜻인지 잘 모르겠지만, 언어와 플랫폼에 상관없이 작동한다는 부분이 참 마음에 든다.

 

 프로토콜 버퍼는 구글이 만들었다고 한다. XML과 비슷하지만 더 작고 빠르고 간단하다. 일단 데이터 구조를 정의해두면 protocol buffers의 소스 코드를 사용해서 다양한 언어와 데이터 스트림에서 쉽게 읽고 쓸 수 있다.

 

 Protocol Buffers는 몇 메가바이트 크기까지 패킷의 직렬화 포맷을 지원한다. 포맷은 네트워크 트래픽과 데이터 저장 모두에 적합하다. Protocol Buffers는 기존 데이터를 재검사하거나 코드를 변경할 필요 없이 새로운 데이터를 확장할 수 있다.

 

 Protocol Buffers의 messages와 services는 개발자가 .proto파일에 작성한다.

// message 작성 예시
message Person {
    optional string name = 1;
    optional int32 id = 2;
    optional string email = 3;
}

 

프로토 컴파일러는 관련된 프로토콜 버퍼를 처리하기 위해 빌드 타임에 .proto파일로부터 다양한 프로그래밍 언어로 코드를 생성한다. 생성된 코드는 전체 구조를 raw bytes로 직렬화하고 파싱하기 위해 각 필드와 메서드에 간단한 접근자를 가진다.

// 생성된 코드를 사용하는 예시(Java)
Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

 

Protocol Buffers의 장점

 Protocol Buffers는 언어 중립적, 플랫폼 중립적이고 확장 가능한 방법으로(language-neutral, platform-neutral, extensible) 구조적이고, 기록적이고, 정형화된 데이터를(structured, record-like, typed data) 직렬화해야하는 어떤 상황에서도 이상적이다. 주로 통신 프로토콜을 정의하고 데이터를 저장하는데 쓰인다.

 

 또 다음과 같은 장점들이 있다.

  • 콤팩트한 데이터 저장
  • 빠른 파싱
  • 다양한 언어에서 사용가능
  • 자동 생성된 클래스들로 최적화된 기능

 같은 메시지는 Protocol Buffers에서 지원하는 어떤 언어로 쓰인 코드에서라도 읽을 수 있다. 구글에서 직접 지원하지 않는 언어라도, 다른 GitHub 프로젝트에서 지원해주는 경우가 있다.

 

 message 타입을 특정 프로젝트의 코드 베이스 바깥에 .proto 파일로 정의함으로써 여러 프로젝트들에 걸쳐 protocol buffers를 사용할 수 있다.

 

몇가지 원칙만 지킨다면, .proto 정의를 변경해도 아무런 문제 없이 새로운 메시지를 읽을 수 있다. 그리고 새로운 코드도 옛날 메시지를 읽을 수 있다. 옛 메시지에 없는 새로운 필드는 기본값으로 제공된다.

 

Protocol Buffers가 적합하지 않는 경우

  • Protocol Buffers는 전체 메시지를 로드 할 수 있다고 가정하기 때문에 몇 메가바이트를 넘는 크기의 데이터에는 적합하지 않다.
  • Protocol Buffers가 직렬화 되어있을 때 동일한 데이터도 다른 바이너리 직렬화를 가질 수 있다. 두 데이터를 비교하려면 완전히 파싱해야한다.
  • Protocol Buffers는 기본적으로 메시지를 압축하지 않는다. JPEG나 PNG를 압축하는데 사용하는 알고리즘들을 사용해서 데이터의 크기를 줄일 수 있다.
  • Protocol Buffers는 과학, 공학에서 사용하는 거대한 다차원 부동소수 배열들 에는 효율적이지 않다.
  • Protocol Buffers는 Fortran이나 IDL같은 비 객체지향적 언어에는 적합하지 않다.

How do Protocol Buffers Work?

 Protocol Buffers가 생성한 코드는 파일과 스트림으로부터 데이터를 받고, 데이터에서 값을 추출하고, 데이터가 존재하는지 확인하고, 데이터를 다시 파일이나 스트림으로 직렬화하는 등 유틸리티 메서드를 제공한다.

 

// Java에서 .proto를 정의하는 예시
message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;
}

 

 이 .proto파일을 컴파일하면 Builder클래스가 생기는데, 이걸로 새 인스턴스를 만들 수 있다.

// Java에서 Builder를 사용하는 예시
Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

 그리고 다른 언어에서 protocol bfufers가 생성한 코드로 데이터를 역직렬화 할 수 있다.

// C++에서 역직렬화 하는 예시
Person john;
fstream input(argv[1], ios::in | ios::binary);
john.ParseFromIstream(&input);
int id = john.id();
std::string name = john.name();
std::string email = john.email();

 

Protocol Buffers Definition Syntax

 .proto 파일을 정의할 때, 먼저 필드가 optional인지 repeated인지 정하거나 그냥 기본으로 둘 수 있다.

 필드가 optional인지 repeated인지 정했다면 자료형을 정해야한다. Protocol buffers는 정수, 불리언, 부동소수와 같은 일반적인 기초 자료형을 지원한다. 필드는 message, enum, oneof, map 타입도 될 수 있다.

 그 다음에는 필드의 이름을 정해야한다. 몇 가지 지켜야할 점이 있다.

  • 일단 출시 되면 필드 이름은 바꾸기 어렵거나 불가능한 경우도 있다.
  • 필드 이름은 대시(-)를 포함할 수 없다.
  • repeated 필드에는 복수형 이름을 사용한다.

 필드 이름을 지정한 다음에는 필드 번호를 지정해야한다. 필드 번호는 재사용될 수 없다. 필드를 삭제했다면 실수로 재사용되는 것을 막기 위해 그 필드 번호는 빈 번호로 남겨두어야한다.

 

 

아래는 실제로 protocol buffers를 프로그래밍 하는데 참고할만한 글이다.

https://protobuf.dev/programming-guides/

 

Programming Guides

Learn how to use Protocol Buffers in your projects.

protobuf.dev

 

'일기' 카테고리의 다른 글

대칭키 암호화와 공개키 암호화  (0) 2025.01.14
protobufjs  (0) 2025.01.08
타워 디펜스 프로젝트  (0) 2025.01.02
OSI 7계층 어플리케이션 계층  (0) 2024.12.30
TCP와 UDP  (0) 2024.12.27