Protocol Buffer

1、什么是 Protocol Buffers?

Protocol Buffers (protobuf) 是一种序列化结构化数据的方法,由 Google 开发。它们提供了一种与语言无关、与平台无关且可扩展的机制,用于高效序列化结构化数据。

  • Protocol Buffers 中的数据结构是在架构文件(.proto 文件)中使用简单的与语言无关的接口定义语言 (IDL) 定义的。
  • Protocol Buffers 将数据序列化为二进制格式。这种二进制格式可通过网络高效传输,并且与基于文本的格式(如 XML 或 JSON)相比,序列化和反序列化速度更快。
  • Protocol Buffers 支持多种编程语言,包括 C++、Java、Python、Go 等。
  • Google 提供了编译器工具(protobuf 编译器),这些工具基于 .proto 架构文件生成这些语言的数据访问类和序列化/反序列化代码。
  • Protocol Buffers 支持向后和向前兼容性。可以将新字段添加到架构中,而不会中断可能仍在使用旧版本架构的现有客户端或服务器。
  • 这使得在大型系统中随时间推移演变数据格式变得更加容易。
  • Protocol Buffers 通常用于对结构化数据进行高效序列化、传输和存储至关重要的场景。这包括网络通信协议(例如 gRPC,默认情况下使用 protobuf)、在数据库中存储数据,以及设计需要有效处理大量数据的 API。

2、示例实现

Protocol Buffers支持以 C++、C#、Dart、Go、Java 和 科特林 / Objective-C、Python 和 Ruby。使用 proto3,您还可以使用 PHP。

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

原型定义

// Java code
Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

使用生成的类来持久保存数据。

// C++ code
Person john;
fstream input(argv[1],
    ios::in | ios::binary);
john.ParseFromIstream(&input);
id = john.id();
name = john.name();
email = john.email();

使用生成的类解析持久化数据

// C++ code
Person john;
fstream input(argv[1],
    ios::in | ios::binary);
john.ParseFromIstream(&input);
id = john.id();
name = john.name();
email = john.email();

3、protobuf-net

protobuf-net是用于.NET代码的基于契约的序列化程序,它以Google设计的"protocol buffers"序列化格式写入数据,适用于大多数编写标准类型并可以使用属性的.NET语言。

protobuf-net可通过NuGet安装程序包,也可直接访问github下载源码:https://github.com/protobuf-net/protobuf-nethttps://github.com/protobuf-net/protobuf-net 下面的代码参考:C#中protobuf-net的编码结构及使用方法 - 二次元攻城狮 - 博客园

using System;
using System.IO;

/// <summary>
/// ProtoBuf-Net扩展方法类
/// </summary>
public static class ProtoBufExtension
{
    /// <summary>
    /// 将对象实例序列化为字符串(Base64编码格式)------ProtoBuf
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="obj">对象实例</param>
    /// <returns>字符串(Base64编码格式)</returns>
    public static string SerializeToString_PB<T>(this T obj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            ProtoBuf.Serializer.Serialize(ms, obj);
            return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
        }
    }

    /// <summary>
    /// 将字符串(Base64编码格式)反序列化为对象实例------ProtoBuf
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="txt">字符串(Base64编码格式)</param>
    /// <returns>对象实例</returns>
    public static T DeserializeFromString_PB<T>(this string txt)
    {
        byte[] arr = Convert.FromBase64String(txt);
        using (MemoryStream ms = new MemoryStream(arr))
            return ProtoBuf.Serializer.Deserialize<T>(ms);
    }

    /// <summary>
    /// 将对象实例序列化为字节数组------ProtoBuf
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="obj">对象实例</param>
    /// <returns>字节数组</returns>
    public static byte[] SerializeToByteAry_PB<T>(this T obj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            ProtoBuf.Serializer.Serialize(ms, obj);
            return ms.ToArray();
        }
    }

    /// <summary>
    /// 将字节数组反序列化为对象实例------ProtoBuf
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="arr">字节数组</param>
    /// <returns></returns>
    public static T DeserializeFromByteAry_PB<T>(this byte[] arr)
    {
        using (MemoryStream ms = new MemoryStream(arr))
            return ProtoBuf.Serializer.Deserialize<T>(ms);
    }

    /// <summary>
    /// 将对象实例序列化为二进制文件------ProtoBuf
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="obj">对象实例</param>
    /// <param name="path">文件路径(目录+文件名)</param>
    public static void SerializeToFile_PB<T>(this T obj, string path)
    {
        using (var file = File.Create(path))
        {
            ProtoBuf.Serializer.Serialize(file, obj);
        }
    }

    /// <summary>
    /// 将二进制文件反序列化为对象实例------ProtoBuf
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <returns></returns>
    public static T DeserializeFromFile_PB<T>(this string path)
    {
        using (var file = File.OpenRead(path))
        {
            return ProtoBuf.Serializer.Deserialize<T>(file);
        }
    }
}

使用参考

static void Main(string[] args)
{

    var person = new Person
    {
        Id = 12345,
        Name = "Fred",
        Address = new Address
        {
            Line1 = "Flat 1",
            Line2 = "The Meadows"
        }
    };

    string str = person.SerializeToString_PB();            
    var strPerson = str.DeserializeFromString_PB<Person>();
    Console.WriteLine("序列化结果(字符串):" + str);

    var arr = person.SerializeToByteAry_PB();
    var arrPerson = arr.DeserializeFromByteAry_PB<Person>();
    Console.WriteLine("序列化结果(字节数组):" + BitConverter.ToString(arr));

    string path = "person.bin";            
    person.SerializeToFile_PB(path);
    var pathPerson = path.DeserializeFromFile_PB<Person>();
    Console.WriteLine("序列化结果(二进制文件):" + BitConverter.ToString(File.ReadAllBytes(path)));

    Console.ReadLine();
}

序列化结果

序列化结果(字符串):CLlgEgRGcmVkGhUKBkZsYXQgMRILVGhlIE1lYWRvd3M=
序列化结果(字节数组):08-B9-60-12-04-46-72-65-64-1A-15-0A-06-46-6C-61-74-20-31-12-0B-54-68-65-20-4D-65-61-64-6F-77-73
序列化结果(二进制文件):08-B9-60-12-04-46-72-65-64-1A-15-0A-06-46-6C-61-74-20-31-12-0B-54-68-65-20-4D-65-61-64-6F-77-73
相关推荐
技术小齐26 分钟前
网络运维学习笔记 016网工初级(HCIA-Datacom与CCNA-EI)PPP点对点协议和PPPoE以太网上的点对点协议(此处只讲华为)
运维·网络·学习
ITPUB-微风32 分钟前
Service Mesh在爱奇艺的落地实践:架构、运维与扩展
运维·架构·service_mesh
落幕1 小时前
C语言-进程
linux·运维·服务器
chenbin5201 小时前
Jenkins 自动构建Job
运维·jenkins
java 凯1 小时前
Jenkins插件管理切换国内源地址
运维·jenkins
AI服务老曹1 小时前
运用先进的智能算法和优化模型,进行科学合理调度的智慧园区开源了
运维·人工智能·安全·开源·音视频
shimly1234562 小时前
tcpdump 用法示例
网络·测试工具·tcpdump
sszdzq3 小时前
Docker
运维·docker·容器
book01213 小时前
MySql数据库运维学习笔记
运维·数据库·mysql
bugtraq20214 小时前
XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux
linux·运维·ubuntu