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
相关推荐
O。o.尊都假都26 分钟前
003__系统共享工具、服务器的使用
linux·运维·服务器
叱咤少帅(少帅)3 小时前
Ubuntu Server安装谷歌浏览器
linux·运维·ubuntu
网络安全Ash4 小时前
全国知名网络安全赛事西湖论剑·杭州网络安全技能大赛启动报名
网络·安全·web安全
聚名网5 小时前
加固服务器有什么用?
运维·服务器
比钻石还闪亮的nan人6 小时前
ubuntu 使用s3fs配置自动挂载对象存储
linux·运维·ubuntu
m0_634601666 小时前
2025.1.2
java·服务器·数据库
Spiffo_Sir6 小时前
【Spiffo】排障:VsCode报错“过程试图写入的管道不存在”(网络环境正常且地址正常的情况下依然出现)
网络·ide·vscode
MAR-Sky6 小时前
集线器,交换机,路由器,mac地址和ip地址知识记录总结
网络·tcp/ip·智能路由器
柒烨带你飞6 小时前
热备份路由HSRP及配置案例
网络·智能路由器
whp4047 小时前
docker-compose 简单部署
运维·docker·容器