读Muduo源码笔记---7(Protobuf)

本文介绍了Protocol Buffers的反射功能,包括Message、Descriptor和Reflection的概念,以及如何通过反射实现动态读写PB字段。详细讲解了序列化与反序列化的过程,并展示了protobuf在Muduo框架中的编解码器和消息分发器的实现原理,重点解析了 ProtobufCodec 和 ProtobufDispatcher 的工作方式。
摘要由CSDN通过智能技术生成

1、概念

   Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
    将 程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化” (Deserialization)。

     简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻 松地存储和传输数据。

  序列化:将对象变成字节流的形式传出去。      反序列化:从字节流恢复成原来的对象。

protobuf的反射功能

  

  1. Message:Person是自定义的pb类型,继承自Message. MessageLite作为Message基类,更加轻量级一些。
    通过Message的两个接口GetDescriptor/GetReflection,可以获取该类型对应的Descriptor/Reflection。

  2. Descriptor:Descriptor是对message类型定义的描述,包括message的名字、所有字段的描述、原始的proto文件内容等,提供的接口:获取所有字段的个数:int field_count() const   获取单个字段描述类型FieldDescriptor的接口 。

  3. FieldDescriptor:描述message中的单个字段,例如字段名,字段属性(optional/required/repeated)等。

  4. Reflection:提供了动态读写pb字段的接口,对pb对象的自动读写主要通过该类完成。对每种类型,Reflection都提供了一个单独的接口用于读写字段对应的值。

//读操作
virtual int32  GetInt32 (const Message& message,const FieldDescriptor* field) const = 0;

virtual int64  GetInt64 (const Message& message,const FieldDescriptor* field) const = 0;

//对于枚举和嵌套的message

virtual const EnumValueDescriptor* GetEnum(const Message& message, const FieldDescriptor* field) const = 0;

virtual const Message& GetMessage(const Message& message,const FieldDescriptor* field,MessageFactory* factory = NULL) const = 0;

       反射使用

  • 通过类型名创建类型对象
// 先获得类型的Descriptor .
    auto descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("T.Test");
    if (nullptr == descriptor)
    {
        return 0 ;
    }
    // 利用Descriptor拿到类型注册的instance. 这个是不可修改的.
    auto prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
    if ( nullptr == descriptor)
    {
        return 0 ;
    }
    // 构造一个可用的消息.
    auto message = prototype->New();
    // 只有当我们预先编译了test消息并且正确链接才能这么干.
    auto test = dynamic_cast<T::Test*>(message);
    // 直接调用message的具体接口
    // 其实这些接口是语法糖接口.所以并没有对应的反射机制来对应调用.
    // 反射机制实现了的Set/Get XXX系列接口,是属于Reflection的接口,接收Message作为参数.
    test->set_id(1);
  • 通过对象和对象的属性的名字获取、修改对应的属性
// 拿到一个对象,不在乎怎么拿到,可以是通过反射拿到。
    // 这里简单直接的创建一个.
    T::Test p_test ;
    // 拿到对象的描述包.
    auto descriptor = p_test.GetDescriptor() ;
    // 拿到对象的反射配置.
    auto reflecter = p_test.GetReflection() ;
    // 拿到属性的描述包.
    auto field = descriptor->FindFieldByName("id");
    // 设置属性的值.
    reflecter->SetInt32(&p_test , field , 5 ) ;
    // 获取属性的值.
    std::cout<<reflecter->GetInt32(p_test , field)<< std::endl 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值