Apollo详解之bridge模块——udp_bridge_sender_component

udp_bridge_sender_component简要介绍

udp_bridge_sender_component的功能是订阅Apollo的话题,并将话题中的protobuf数据发送给目的IP地址。

使用方法

modules/bridge/conf文件夹下,可以找到对应的配置文件,修改其中的参数,定义目标IP地址,端口号,protobuf数据类型。若要添加新的数据类型可参考 modules/bridge/README.md文件。

udp_bridge_sender_component简要分析

该文件定义了一个类UDPBridgeSenderComponent,可以从头文件中看出,其继承于cyber::Component,即该类由cyber RT框架动态加载。
其有两个主要的成员函数,UDPBridgeSenderComponent<T>::Init()相当于main函数,该函数较为简单,完成了从配置文件中读取目的IP地址、端口号等信息的功能。
UDPBridgeSenderComponent<T>::Proc(const std::shared_ptr<T> &pb_msg)相当于订阅者的回调函数,其形参pb_msg为订阅得到的protobuf数据,实现的功能是将protobuf数据以UDP协议发送给目的IP地址。

数据格式

在进一步分析之前,首先需要了解一下Apollo的bridge模块UDP数据的格式。
Apollo的bridge模块通过UDP协议发送的基本数据被称为,其由首部数据组成。在UDPBridgeSenderComponent<T>::Proc函数当中,protobuf数据首先进行序列化,然后将其根据参数FRAME_SIZE分割为一个个大小相同的数据块,为每个数据块添加首部后,就组成了一个个的帧,然后将所有的帧发送发送。
帧的格式如下:

  1. BRIDGE_HEADER_FLAG。用于标识bridge模块的数据
  2. hsize。通过typedef定义的数据类型,用于表示首部的大小
  3. 各类的首部信息,其格式为HType:bsize:value\n,分别表示首部信息的枚举类型HType、该首部信息value的大小bsize、首部信息value。枚举类型HType定义如下:
    1. Header_Ver。版本
    2. Msg_Name。protobuf数据类型名,用于标识该protobuf数据的类型
    3. Msg_ID。protobuf数据ID,用于唯一标识一个protobuf数据
    4. Msg_Size。protobuf数据序列化后的总字节数,注意不包含首部
    5. Msg_Frames。该protobuf数据的总帧数
    6. Frame_Size。该帧的字节数,包含帧首部和数据
    7. Frame_Pos。该帧的数据在序列化protobuf数据中的位置,用于将各个帧中的数据组装回protobuf数据
    8. Frame_Index。每个帧从零开始的序号,用于标识帧的顺序
    9. Time_Stamp。时间戳
    10. Header_Tail。用于表示枚举成员的个数(不包含该枚举成员)

数据发送

UDPBridgeSenderComponent<T>::Proc函数当中,会实例化一个BridgeProtoSerializedBuf对象,调用成员函数Serialize将protobuf数据进行序列化,通过计算和protobuf数据当中的一部分信息获得首部,得到一个个的帧,并将所有的帧保存到的数据成员当中,并通过for循环将其发送给目的地址,相关代码:

  // 创建序列化对象,将protobuf序列化并分割为一个个带有首部信息的帧,并将其全部发送给目的地址
  BridgeProtoSerializedBuf<T> proto_buf;
  proto_buf.Serialize(pb_msg, proto_name_);
  for (size_t j = 0; j < proto_buf.GetSerializedBufCount(); j++) {
    ssize_t nbytes = send(sock_fd, proto_buf.GetSerializedBuf(j),
                          proto_buf.GetSerializedBufSize(j), 0);
    // 若发生的数据和帧的大小不一致,则停止之后的发送
    if (nbytes != static_cast<ssize_t>(proto_buf.GetSerializedBufSize(j))) {
      break;
    }
  }

到此即完成了protobuf数据的发送。
由个人能力有限,如有错误,请在评论中指出,不胜感谢!

上一篇:rsync算法原理和工作流程分析


下一篇:一行代码设置颜色的控件