프로토콜 버퍼 소개

프로토콜 버퍼(또는 protobuf)는 구조화된 데이터를 직렬화하는 방법이며 제약 시스템 간의 통신에 이상적입니다. 언어 중립적이고 플랫폼 중립적이며 2001년부터 Google에서 개발 및 사용했습니다. 2008년에 대중에게 공개되었습니다(무료 및 오픈 소스). 공식 문서 및 소스 코드는 다음 링크에서 사용할 수 있습니다.
  • Official documentation
  • Protocol buffers source code

  • 프로토콜 버퍼가 작동하는 방식은 통신하려는 모든 정보를 캡슐화하는 스키마를 정의하고 이를 proto 파일에 저장하는 것입니다. 시간과 날짜가 포함된 알람 상태 이벤트를 전송하고 싶다고 가정해 보겠습니다. 그런 다음 아래와 같은 AlarmStatus.proto라는 스키마를 생성할 수 있습니다.

        // AlarmStatus.proto
        syntax = "proto3";
    
        message AlarmStatus {
            bool alarm_active = 1;
            string time_utc   = 2;
            string date_utc   = 3;
        }
    


    그로부터 프로토콜 버퍼 데이터의 인코딩/디코딩을 구현하는 언어별 클래스를 생성하기 위해 protobuf 컴파일러를 사용합니다.

    Protobuf 컴파일러 설치



    프로토콜 컴파일러(protoc)는 protobuf 스키마를 이진 클래스로 변환하기 위한 공통 도구 체인이며 컴파일하려는 언어에 관계없이 필요합니다.
  • 다운로드 페이지에서 당사의 개발 환경에 맞는 최신 protoc 사전 빌드 바이너리를 다운로드하십시오: protoc-$VERSION-$PLATFORM.zip.
  • zip 파일의 압축을 원하는 폴더에 풀고 protoc 실행 파일이 포함된 폴더를 가리키는 환경 변수를 추가합니다.

  •     C:\protoc-3.17.3-win64\bin
    


    모든 것이 올바르게 설정되면 모든 작업 디렉토리에서 protoc.exe를 실행할 수 있어야 합니다.



    Python을 사용하는 프로토콜 버퍼



    메시지 정의에서 Python 컴파일 프로토콜 버퍼 생성

    download page 에서 Python용 최신 프로토콜 버퍼 패키지를 다운로드하고 지침은 README.md를 따르십시오.

    이 시점에서 pip list를 실행하면 protobuf가 설치된 것을 확인할 수 있습니다.

        PS D:\Downloads\protobuf-3.17.3\python> pip list
        Package    Version
        ---------- -------
        pip        21.1.2
        protobuf   3.17.3
        setuptools 56.0.0
        six        1.16.0
        wheel      0.36.2
    


    protobuf 스키마를 생성했으므로 다음 명령을 사용하여 관련 Python 클래스 파일을 쉽게 생성할 수 있습니다.

        PS D:\Workspace\ProtobufDemo> protoc --python_out=. *.proto
    


    스키마에서 Python 클래스 생성

    Python을 사용한 Protobuf 직렬화

    protobuf 메시지를 직렬화하려면 메시지를 생성하고 채운 다음 SerializeToString() 를 호출하면 됩니다.

        # SerialisationDemo.py
    
        import random
        from datetime import datetime, timezone
        from AlarmStatus_pb2 import AlarmStatus
    
        def get_new_alarm_status():
            date_time_utc = datetime.now(timezone.utc)
            alarm_status = AlarmStatus()
            alarm_status.alarm_active = bool(random.getrandbits(1))
            alarm_status.time_utc = "{}".format(date_time_utc.time())
            alarm_status.date_utc = "{}".format(date_time_utc.date())
    
            return alarm_status
    
        def serialise_alarm_status(alarm_status):
            return alarm_status.SerializeToString()
    
        def main():
            alarm_status = get_new_alarm_status()
            print("Alarm status: {}, time: {}, date: {}".format(alarm_status.alarm_active, alarm_status.time_utc, alarm_status.date_utc))
    
            serialised_alarm_status = serialise_alarm_status(alarm_status)
            print("Serialised data: {}".format(serialised_alarm_status))
    
        if __name__ == "__main__":
            main()
    




    Python을 사용한 Protobuf 역직렬화

    protobuf 메시지를 역직렬화하려면 메시지를 만든 다음 직렬화된 데이터를 전달하는 ParseFromString()을 호출합니다.

        # SerialisationDemo.py
    
        import random
        from datetime import datetime, timezone
        from AlarmStatus_pb2 import AlarmStatus
    
        def get_new_alarm_status():
            date_time_utc = datetime.now(timezone.utc)
            alarm_status = AlarmStatus()
            alarm_status.alarm_active = bool(random.getrandbits(1))
            alarm_status.time_utc = "{}".format(date_time_utc.time())
            alarm_status.date_utc = "{}".format(date_time_utc.date())
    
            return alarm_status
    
        def serialise_alarm_status(alarm_status):
            return alarm_status.SerializeToString()
    
        def deserialise_alarm_status(serialised_alarm_status):
            alarm_status = AlarmStatus()
            alarm_status.ParseFromString(serialised_alarm_status)
    
            return alarm_status
    
        def main():
            alarm_status = get_new_alarm_status()
            print("Alarm status: {}, time: {}, date: {}".format(alarm_status.alarm_active, alarm_status.time_utc, alarm_status.date_utc))
    
            serialised_alarm_status = serialise_alarm_status(alarm_status)
            print("Serialised data: {}".format(serialised_alarm_status))
    
            alarm_status2 = deserialise_alarm_status(serialised_alarm_status)
            print("Deserialised alarm status: {}, time: {}, date: {}".format(alarm_status2.alarm_active, alarm_status2.time_utc, alarm_status2.date_utc))
    
        if __name__ == "__main__":
            main()
    




    C를 사용하는 프로토콜 버퍼



    메시지 정의에서 C# 컴파일 프로토콜 버퍼 생성

    protobuf 스키마를 생성했다면 다음 명령을 사용하여 연결된 C# 클래스 파일을 쉽게 생성할 수 있습니다protoc –csharp_out=. *.proto.

        PS D:\Workspace\ProtobufDemo> ls
    
            Directory: D:\Workspace\ProtobufDemo
    
        Mode                 LastWriteTime         Length Name
        ----                 -------------         ------ ----
        -a---          21/07/2021  4:00 pm            128 AlarmStatus.proto
    
        PS D:\Workspace\ProtobufDemo> protoc --csharp_out=. *.proto
        PS D:\Workspace\ProtobufDemo> ls
    
            Directory: D:\Workspace\ProtobufDemo
    
        Mode                 LastWriteTime         Length Name
        ----                 -------------         ------ ----
        -a---          21/07/2021  9:44 pm           9841 AlarmStatus.cs
        -a---          21/07/2021  4:00 pm            128 AlarmStatus.proto
    
        PS D:\Workspace\ProtobufDemo>
    


    C#에서 프로토콜 버퍼 직렬화

    새 콘솔 애플리케이션을 만들고 Google.Protobuf NuGet 패키지를 추가합니다.

        PS D:\Workspace\ProtobufDemo> dotnet new console
        ...
        PS D:\Workspace\ProtobufDemo> ls
    
            Directory: D:\Workspace\ProtobufDemo
    
        Mode                 LastWriteTime         Length Name
        ----                 -------------         ------ ----
        d----          21/07/2021  9:44 pm                obj
        -a---          21/07/2021  9:44 pm           9841 AlarmStatus.cs
        -a---          21/07/2021  4:00 pm            128 AlarmStatus.proto
        -a---          21/07/2021  9:44 pm            194 Program.cs
        -a---          21/07/2021  9:44 pm            171 ProtobufDemo.csproj
    
        PS D:\Workspace\ProtobufDemo> dotnet add package Google.Protobuf
        ...
        PS D:\Workspace\ProtobufDemo>
    


    protobuf 메시지를 직렬화하려면 메시지를 생성하고 채운 다음 ToByteString()을 호출하기만 하면 됩니다.

        using System;
        using Google.Protobuf;
    
        namespace ProtobufDemo
        {
            class Program
            {
                static void Main(string[] args)
                {
                    var alarmStatus = GetNewAlarmStatus();
                    var serialisedAlarmStatus = SerialiseAlarmStatus(alarmStatus);
                    Console.WriteLine($"Alarm status: {alarmStatus.AlarmActive}, time: {alarmStatus.TimeUtc}, date: {alarmStatus.DateUtc}");
                    Console.WriteLine($"Serialised data: {serialisedAlarmStatus}");
                }
    
                private static AlarmStatus GetNewAlarmStatus()
                {
                    var rand = new Random();
                    var status = rand.Next(2) == 1;
                    var dateTime = DateTimeOffset.UtcNow;
    
                    return new AlarmStatus
                    {
                        AlarmActive = status,
                        TimeUtc = dateTime.ToString("T"),
                        DateUtc = dateTime.ToString("d")
                    };
                }
    
                private static ByteString SerialiseAlarmStatus(AlarmStatus alarmStatus)
                {
                    return alarmStatus.ToByteString();
                }
            }
        }
    


    C#을 사용한 Protobuf 직렬화

    C#에서 프로토콜 버퍼 역직렬화

    protobuf 메시지를 역직렬화하려면 직렬화된 메시지를 전달하는 MergeFrom()을 호출하기만 하면 됩니다.

        ...
        static void Main(string[] args)
        {
            ...
    
            var deserialisedAlarmStatus = DeserialiseAlarmStatus(serialisedAlarmStatus);
            Console.WriteLine($"Deserialised alarm status: {deserialisedAlarmStatus.AlarmActive}, time: {deserialisedAlarmStatus.TimeUtc}, date: {deserialisedAlarmStatus.DateUtc}");
        }
    
        ...
    
        private static AlarmStatus DeserialiseAlarmStatus(ByteString serialisedAlarmStatus)
        {
            var deserialisedAlarmStatus = new AlarmStatus();
            deserialisedAlarmStatus.MergeFrom(serialisedAlarmStatus);
    
            return deserialisedAlarmStatus;
        }
        ...
    


    C#을 사용한 Protobuf 역직렬화

    This blog post was originally posted on my blog site An IoT Odyssey

    좋은 웹페이지 즐겨찾기