Apollo 3.5 Cyber 多進程通訊模塊 - Transport (Intra 和 rtps 篇)

Apollo 3.5 Cyber 多進程通訊模塊 - Transport (Intra 和 rtps 篇)

    • Intra 模式
    • RTPS 模式

https://blog.csdn.net/weixin_44450715/article/details/86314193

上一篇說完了shared memory篇後,也要把餘下的Intra 和 rtps 篇給補完了

Intra 模式

先說重點,Intra模式不是做多進程通訊的,而是做單進程內部通訊的。
而其架構基本就是把shared memory版本中的所有shared memory操作,線程安全的代碼去掉就是了。
所以一定要先看上一篇

簡單看一下其IntraDispatcherIntraTransmitter就會明白了(IntraReceiver的實現和ShmReceiver是一樣的)

// IntraDispatcher

template <typename MessageT>
void IntraDispatcher::OnMessage(uint64_t channel_id,
                                const std::shared_ptr<MessageT>& message,
                                const MessageInfo& message_info) {
  if (is_shutdown_.load()) {
    return;
  }
  ADEBUG << "intra on message, channel:"
         << common::GlobalData::GetChannelById(channel_id);
  ListenerHandlerBasePtr* handler_base = nullptr;
  if (msg_listeners_.Get(channel_id, &handler_base)) {
    if ((*handler_base)->IsRawMessage()) {
      auto handler =
          std::dynamic_pointer_cast<ListenerHandler<message::RawMessage>>(
              *handler_base);
      auto msg = std::make_shared<message::RawMessage>();
      message::SerializeToString(*message, &msg->message);
      handler->Run(msg, message_info);
    } else {
      auto handler =
          std::dynamic_pointer_cast<ListenerHandler<MessageT>>(*handler_base);
      if (handler == nullptr) {
        AERROR << "please ensure that readers with the same channel["
               << common::GlobalData::GetChannelById(channel_id)
               << "] in the same process have the same message type";
        return;
      }
      handler->Run(message, message_info);
    }
  }
}

// IntraTransmitter
template <typename M>
bool IntraTransmitter<M>::Transmit(const MessagePtr& msg,
                                   const MessageInfo& msg_info) {
  if (!this->enabled_) {
    ADEBUG << "not enable.";
    return false;
  }

  dispatcher_->OnMessage(channel_id_, msg, msg_info);
  return true;
}

無錯,就是在Transmit時直接把所有相關callback調用,直接簡單。

RTPS 模式

要了解RTPS模式,要先了解rtps(real-time publish subscribe)是甚麼
以下有一些有用的資料

https://wiki.wireshark.org/Protocols/rtps

rtps基本就是一個用來做實時publish subscribe model通訊的protocol
Apollo用了eprosima-fast-rtps的rtps實現。
可以先看一下Docs

At the top of RTPS, we find the Domain, which defines a separate plane of communication. 
Several domains can coexist at the same time independently. 
A domain contains any number of Participants, elements capable of sending and receiving data. 
To do this, the participants use their Endpoints:

Reader: Endpoint able to receive data.
Writer: Endpoint able to send data.

A Participant can have any number of writer and reader endpoints.

比較不一樣的是

Communication revolves around Topics, which define the data being exchanged. 
Topics don’t belong to any participant in particular; instead, 
all interested participants keep track of changes to the topic data and make sure to keep each other up to date. 
The unit of communication is called a Change, which represents an update to a topic. 
Endpoints register these changes on their History, a data structure that serves as a cache for recent changes. 
When you publish a change through a writer endpoint, the following steps happen behind the scenes:

The change is added to the writer’s history cache.
The writer informs any readers it knows about.
Any interested (subscribed) readers request the change.
After receiving data, readers update their history cache with the new change.

By choosing Quality of Service policies, you can affect how these history caches are managed in several ways, but the communication loop remains the same. You can read more information in Configuration.

比起shared memory版的, rtps版多了

  • qos (define quality of service)
  • have history cache in both reader and writer side

不過這幾點對用家影響不大,可直接無視


eprosima-fast-rtps的rtps實現邏輯如上

其concept和apollo內部的channel,receiver,transmitter是差不多的.可是要小心

  1. Domain 不是 channel。在fast-rtps中只有在同一DomainParticipant,可以互相通訊。而cyber中,所有的channel都在用同一個Domain,而設定channel的方法,是設定PublisherAttributesSubscriberAttributes中的一個field: topic

Apollo 3.5 Cyber 多進程通訊模塊 - Transport (Intra 和 rtps 篇)_第1张图片

把RTPS的class也加到了進去圖中了。來說一下rtps模式中獨有的class吧

  • UnderlayMessage,UnderlayMessageType:UnderlayMessage是在rtps通訊中用到的消息類型,不管是甚麼消息類型都會先轉為char buffer(string),然後放到UnderlayMessage的data變量中,再做傳送。而UnderlayMessageType是用來做register的。這兩個class的大部份代碼是由fast rtcp中一個idl工具生成的,不用深究
  • AttributesFiller,QosProfileConf: 要用人家fastrtps的庫,就要跟人家的規距,做一堆配置。配置多了怎辦,寫一個wrapper讓其直接按全局的config去自動配置
  • SubListener: Subscriber + Listener. 負責處理eprosima::fastrtps::Subscriber在收到新message時,調用Listener(Listener == callback)
  • RtpsReceiver,RtpsDispatcher,RtpsTransmitter,就是 Receiver,Dispatcher,Transmitter的具體實現。至於負責甚麼,可以看上一篇

而rtps模式下的很多細節都藏在fastrtps這庫中了,在cyber中只要把createSubscribercreatePublisher設定好,就一切完事了

// Study: Create a subscriber, and call the callback when message come
  new_sub.sub_listener = std::make_shared<SubListener>(
      std::bind(&RtpsDispatcher::OnMessage, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3));

  new_sub.sub = eprosima::fastrtps::Domain::createSubscriber(
      participant_->fastrtps_participant(), sub_attr,
      new_sub.sub_listener.get());

// Study: Create a publisher, and publish the data to subscriber
 eprosima::fastrtps::PublisherAttributes pub_attr;
  RETURN_IF(!AttributesFiller::FillInPubAttr(
      this->attr_.channel_name(), this->attr_.qos_profile(), &pub_attr));
  publisher_ = eprosima::fastrtps::Domain::createPublisher(
      participant_->fastrtps_participant(), pub_attr);
      ```

你可能感兴趣的:(apollo)