티스토리 뷰

C언어

protocol buffer

바람사탕 2024. 5. 29. 23:42
반응형

Protocol Buffers (프로토콜 버퍼) 또는 protobuf는 구글에서 개발한 언어 중립적이고 플랫폼 중립적인 직렬화 라이브러리입니다. 데이터를 구조화된 방식으로 직렬화하고 역직렬화하기 위한 메커니즘을 제공합니다. 주로 원격 프로시저 호출(RPC), 데이터 저장, 네트워크 전송 등에서 사용됩니다.

주요 특징

1. 효율성: 바이트 단위의 이진 포맷을 사용하여 직렬화되므로, JSON이나 XML에 비해 훨씬 더 작은 크기와 빠른 속도를 자랑합니다.
2. 언어 중립성: 여러 언어(C++, Java, Python, Go 등)에서 사용할 수 있습니다.
3. 확장성: 프로토콜 버퍼는 하위 호환성을 유지하면서 스키마를 쉽게 확장할 수 있습니다.

기본 사용법

1. '.proto' 파일 작성

프로토콜 버퍼를 사용하려면 먼저 메시지 타입을 정의하는 '.proto' 파일을 작성합니다.


syntax = "proto3";

message Person {
  int32 id = 1;
  string name = 2;
  string email = 3;
}


- 'syntax = "proto3";': 사용하려는 프로토콜 버퍼의 버전을 지정합니다. (현재는 proto3)
- 'message Person': 'Person'이라는 메시지 타입을 정의합니다.
- 'int32 id = 1;': 'id' 필드는 'int32' 타입이며, 필드 번호는 1입니다.
- 'string name = 2;': 'name' 필드는 'string' 타입이며, 필드 번호는 2입니다.
- 'string email = 3;': 'email' 필드는 'string' 타입이며, 필드 번호는 3입니다.

2. 코드 생성

'protoc' 컴파일러를 사용하여 '.proto' 파일로부터 코드 생성합니다. 예를 들어, Python용 코드를 생성하려면 다음 명령을 사용합니다:

sh
protoc --python_out=. person.proto


이 명령은 'person_pb2.py' 파일을 생성합니다.

3. 생성된 코드 사용

생성된 코드를 사용하여 메시지를 생성, 직렬화, 역직렬화합니다.

python
import person_pb2

# 메시지 생성
person = person_pb2.Person()
person.id = 1234
person.name = "John Doe"
person.email = "john.doe@example.com"

# 직렬화
serialized_person = person.SerializeToString()

# 역직렬화
new_person = person_pb2.Person()
new_person.ParseFromString(serialized_person)

print(new_person)


필드 타입

프로토콜 버퍼는 다양한 기본 필드 타입을 지원합니다:
- 정수형: 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64', 'fixed32', 'fixed64', 'sfixed32', 'sfixed64'
- 부동 소수점: 'float', 'double'
- 논리형: 'bool'
- 문자열: 'string'
- 바이트: 'bytes'

반복 필드

반복 필드는 여러 값을 가질 수 있는 배열과 유사합니다.


message Person {
  repeated string phone_numbers = 4;
}


중첩 메시지

메시지 안에 다른 메시지를 중첩시킬 수 있습니다.


message Address {
  string street = 1;
  string city = 2;
}

message Person {
  int32 id = 1;
  string name = 2;
  Address address = 3;
}


선택적 필드와 기본값

proto3에서는 모든 필드가 기본적으로 선택적입니다. 필드가 설정되지 않으면 기본값을 가집니다.

요약

프로토콜 버퍼는 효율적이고 확장 가능한 데이터 직렬화 포맷입니다. 네트워크 전송, 데이터 저장 및 기타 다양한 애플리케이션에서 데이터 직렬화 작업을 단순화하고 성능을 개선할 수 있습니다. '.proto' 파일을 작성하고 'protoc' 컴파일러를 사용하여 다양한 언어로 코드를 생성한 후, 생성된 코드를 사용하여 데이터를 직렬화하고 역직렬화할 수 있습니다.

 

 

 

 

c예제

Protocol Buffers를 사용하여 C에서 데이터를 직렬화하고 역직렬화하는 예제를 제공하겠습니다. C에서 Protobuf를 사용하려면 'protobuf-c' 라이브러리를 사용해야 합니다.

1. .proto 파일 작성
2. protoc 컴파일러를 사용하여 C 코드를 생성
3. 생성된 C 코드를 사용하여 메시지 직렬화 및 역직렬화

1. .proto 파일 작성

먼저, 메시지 타입을 정의하는 '.proto' 파일을 작성합니다. 예를 들어, 'person.proto' 파일을 작성합니다.

proto
syntax = "proto3";

message Person {
  int32 id = 1;
  string name = 2;
  string email = 3;
}


2. protoc 컴파일러를 사용하여 C 코드를 생성

'protoc' 컴파일러와 'protobuf-c' 플러그인을 사용하여 '.proto' 파일로부터 C 코드를 생성합니다.

sh
protoc-c --c_out=. person.proto


이 명령은 'person.pb-c.h' 및 'person.pb-c.c' 파일을 생성합니다. 이 파일들은 C 코드에서 사용될 것입니다.

3. 생성된 C 코드를 사용하여 메시지 직렬화 및 역직렬화

이제 생성된 코드를 사용하여 C 프로그램을 작성합니다.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "person.pb-c.h"

int main() {
    // Create a new Person message
    Person person = PERSON__INIT;

    person.id = 1234;
    person.name = "John Doe";
    person.email = "john.doe@example.com";

    // Serialize the message to a buffer
    size_t len = person__get_packed_size(&person);
    void *buffer = malloc(len);
    person__pack(&person, buffer);

    // Print the serialized data as a hex string
    printf("Serialized data:");
    for (size_t i = 0; i < len; i++) {
        printf(" %02x", ((uint8_t*)buffer)[i]);
    }
    printf("\n");

    // Deserialize the message from the buffer
    Person *person_deserialized = person__unpack(NULL, len, buffer);
    if (person_deserialized == NULL) {
        fprintf(stderr, "Error unpacking message\n");
        free(buffer);
        return 1;
    }

    // Print the deserialized message
    printf("Deserialized data:\n");
    printf("ID: %d\n", person_deserialized->id);
    printf("Name: %s\n", person_deserialized->name);
    printf("Email: %s\n", person_deserialized->email);

    // Clean up
    person__free_unpacked(person_deserialized, NULL);
    free(buffer);

    return 0;
}

 

 

 

1. 프로토콜 버퍼 메시지 초기화:
   - 'Person person = PERSON__INIT;'를 사용하여 메시지를 초기화합니다.

2. 메시지 필드 설정:
   - 'person.id', 'person.name', 'person.email'을 설정하여 메시지 필드를 채웁니다.

3. 메시지 직렬화:
   - 'person__get_packed_size(&person)'를 사용하여 직렬화된 메시지의 크기를 계산합니다.
   - 'malloc'을 사용하여 버퍼를 할당하고, 'person__pack(&person, buffer)'를 사용하여 메시지를 직렬화합니다.

4. 직렬화된 데이터 출력:
   - 직렬화된 데이터를 16진수 형식으로 출력합니다.

5. 메시지 역직렬화:
   - 'person__unpack(NULL, len, buffer)'를 사용하여 직렬화된 데이터를 역직렬화합니다.

6. 역직렬화된 메시지 출력:
   - 역직렬화된 메시지의 필드를 출력합니다.

7. 메모리 정리:
   - 'person__free_unpacked(person_deserialized, NULL)'를 사용하여 역직렬화된 메시지의 메모리를 해제하고, 'free(buffer)'를 사용하여 직렬화된 데이터의 버퍼를 해제합니다.

종속성 설치

이 예제를 실행하려면 'protobuf-c' 라이브러리가 필요합니다. 이를 설치하려면 다음 명령을 사용하십시오:

sudo apt-get install protobuf-c-compiler protobuf-c-dev


이제 이 예제를 사용하여 C에서 Protocol Buffers를 사용할 수 있습니다.

 

 

 

 

 

 

 

 

Protocol Buffers (Protobuf)의 장점과 단점

장점

1. 효율성:
   - 소형 크기: Protobuf는 데이터를 이진 포맷으로 직렬화하므로, JSON이나 XML에 비해 데이터 크기가 작습니다. 이는 전송 및 저장 시 더 적은 공간을 차지합니다.
   - 고속: 이진 포맷을 사용하기 때문에, 직렬화 및 역직렬화 속도가 빠릅니다.

2. 언어 중립성:
   - 여러 언어(C++, Java, Python, Go 등)에서 사용 가능하여, 다양한 환경에서 데이터 교환이 가능합니다.

     C언어는 직접적으로 지원하지 않음.

3. 플랫폼 중립성:
   - 다양한 플랫폼에서 동일한 방식으로 동작합니다. 서버, 클라이언트, 모바일 등 다양한 환경에서 쉽게 적용할 수 있습니다.

4. 확장성:
   - 스키마가 변경되더라도 하위 호환성을 유지할 수 있습니다. 새로운 필드를 추가해도 기존의 클라이언트와 서버가 이를 무시하고 계속 통신할 수 있습니다.

5. 자동 코드 생성:
   - `.proto` 파일을 기반으로 여러 언어에 대한 직렬화/역직렬화 코드를 자동으로 생성해 주어 개발자 부담을 줄입니다.

6. 강력한 타입 시스템:
   - 엄격한 타입 시스템을 사용하여 데이터의 무결성을 보장합니다. 이는 코드 작성 시 타입 오류를 줄이는 데 도움이 됩니다.

단점

1. 이진 포맷:
   - Protobuf는 이진 포맷을 사용하기 때문에 사람이 읽기 어렵습니다. 디버깅 및 로그 분석 시 가독성이 떨어질 수 있습니다.

2. 초기 학습 곡선:
   - Protobuf를 처음 사용하는 개발자는 `.proto` 파일 작성 및 `protoc` 컴파일러 사용 방법을 익혀야 하므로 초기 학습 곡선이 존재합니다.

3. 복잡한 스키마 변경:
   - 스키마 변경이 하위 호환성을 유지하더라도 복잡한 스키마 변경이 필요할 때는 주의가 필요합니다. 특히 필드 번호를 변경하면 하위 호환성이 깨질 수 있습니다.

4. 추가 종속성:
   - Protobuf를 사용하려면 관련 라이브러리와 툴체인을 설치하고 관리해야 합니다. 이는 프로젝트의 복잡성을 증가시킬 수 있습니다.

5. 제한된 데이터 타입:
   - Protobuf는 일부 데이터 타입에 제한이 있습니다. 예를 들어, JSON의 동적 속성이나 XML의 임의의 중첩 구조를 표현하는 데 어려움이 있을 수 있습니다.

6. 기능 제한:
   - Protobuf는 주로 데이터 직렬화에 중점을 두고 있으므로, JSON이나 XML이 제공하는 일부 메타데이터 기능을 지원하지 않을 수 있습니다.

 

7. 코드 크기 대폭 증가:
   - 프로토콜 코드가 자동으로 생성되며, 그 크기가 상당히 큽니다.

 

8. 효율성:

  - 고전적인 바이너리 통신 프로토콜에 비해 큰 메리트가 없습니다.

    코드도 매우 복잡하고, 제약사항, 개발/유지보수 절차 등도 잘 알고 있어야 합니다.

 - 통신 프로토콜 분석이 쉽지 않습니다.

   고전적인 통신 프로토콜은 통신 프로토콜을 사람이 이해하기 쉽게 작성하고, 그에 맞게 구현하기 때문에 이해가 쉬우나, Protobuf는 많은 데이터형이 존재하게 되어, 이해하기가 어렵습니다.

.
요약

Protocol Buffers는 효율적인 데이터 직렬화 포맷으로, 다양한 언어와 플랫폼에서 사용될 수 있습니다. 데이터 크기를 줄이고 직렬화/역직렬화 속도를 높이는 등의 장점이 있지만, 이진 포맷으로 인해 가독성이 떨어지고 초기 학습 곡선이 존재하는 등의 단점도 있습니다. Protobuf의 장점과 단점을 잘 이해하고 사용 사례에 적합한지를 평가하는 것이 중요합니다.

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함