FastDDS 源码解析(二十)处理acknack消息

320 阅读12分钟

第一篇 一个例子

车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用

第二篇fastdds的组成

车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)

车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)

车载消息中间件FastDDS 源码解析(四)RtpsParticipant的创建(下)

车载消息中间件FastDDS 源码解析(五)BuiltinProtocols(上)

车载消息中间件FastDDS 源码解析(六)BuiltinProtocols(中)EDP

车载消息中间件FastDDS 源码解析(七)BuiltinProtocols(下)WLP&TypeLookupManager

车载消息中间件FastDDS 源码解析(八)TimedEvent

车载消息中间件FastDDS 源码解析(九)Message

第三篇组网建立连接

pdp建连

车载消息中间件FastDDS 源码解析(十)发送第一条PDP消息(上)

FastDDS 源码解析(十一)发送第一条PDP消息(中)

FastDDS 源码解析(十二)发送第一条PDP消息(下)---异步发送

FastDDS 源码解析(十三)发送第一条PDP消息---跨进程发送

FastDDS 源码解析(十四)接收PDP消息(上)

FastDDS 源码解析(十五)接收PDP消息(下)

FastDDS 源码解析(十六)处理PDP消息——PDP匹配

EDP建连

FastDDS 源码解析(十七)处理PDP消息——EDP匹配

FastDDS 源码解析(十八)EDP阶段发送心跳heartbeat

FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息

1.StatefulWriter处理acknack消息

1.1时序图

sequenceDiagram
		participant UDPChannelResource
		participant ReceiverResource
		participant MessageReceiver		
		participant StatefulWriter
    participant ReaderProxy
		UDPChannelResource ->> UDPChannelResource: 1.perform_listen_operation()
		UDPChannelResource ->> UDPChannelResource: 2.Receive()
		UDPChannelResource ->> ReceiverResource: 3.OnDataReceived()
		ReceiverResource ->> MessageReceiver: 4.processCDRMsg()
		MessageReceiver ->> MessageReceiver: 5.proc_Submsg_Acknack()
		MessageReceiver ->> StatefulWriter: 6.process_acknack()
		StatefulWriter ->> ReaderProxy: 7.check_and_set_acknack_count()
		StatefulWriter ->> ReaderProxy: 8.acked_changes_set()
		StatefulWriter ->> ReaderProxy: 9.requested_changes_set()
		StatefulWriter ->> StatefulWriter: 10.nack_response_event_.restart_timer()
		StatefulWriter ->> ReaderProxy: 11.process_initial_acknack()
    StatefulWriter ->> StatefulWriter: 12.check_acked_status()

1.-4.可以参看FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息1.1节内容

5.proc_Submsg_Acknack 解析各个字节的消息,解析完成后主要是调用StatefulWriter的process_acknack

6.StatefulWriter的process_acknack 主要调用了如下函数

a.ReaderProxy::check_and_set_acknack_count 见7

b.ReaderProxy::acked_changes_set 见8

c.ReaderProxy::requested_changes_set 见9

d.ReaderProxy::process_initial_acknack 见10

e.check_acked_status 见11

7.ReaderProxy::check_and_set_acknack_count

主要是查看一下这个acknack消息是不是最新的acknack,不是的话不处理,如果是的话处理这个acknack消息

8:ReaderProxy::acked_changes_set

传入的参数是readerSNState的base,

根据readerSNState的base,增加或者减少changes_for_reader_ 中的消息。

9:ReaderProxy::requested_changes_set

将changes_for_reader_ 中相应的SequenceNumber的消息状态设置成REQUESTED,nack_response_event_ 启动。

如果没找到这个SequenceNumber的消息,相当于这个消息在writer这儿没有,将这个SequenceNumber放入gap_builder,为之后构建gap消息做准备。

10.nack_response_event_ 启动,这个启动就是将请求的数据发出去。

11:ReaderProxy::process_initial_acknack

如果是本地的reader发送过来的acknack,则将所有状态为 UNACKNOWLEDGED的消息状态设置为UNSENT,然后将消息通过flow_controller_发送出去

如果是remote的reader,writer发送heartbeat给reader

12:check_acked_status

一些新的被所有的reader收到的消息,需要处理一下调用onWriterChangeReceivedByAll,如果消息是VOLATILE类型的,会被从history 中删除。

1.2源码

步骤5:

 bool MessageReceiver::proc_Submsg_Acknack(
         CDRMessage_t* msg,
         SubmessageHeader_t* smh) const
 {
     eprosima::shared_lock<eprosima::shared_mutex> guard(mtx_);
 ​
     bool endiannessFlag = (smh->flags & BIT(0)) != 0;
     bool finalFlag = (smh->flags & BIT(1)) != 0;
     //Assign message endianness
     if (endiannessFlag)
     {
         msg->msg_endian = LITTLEEND;
     }
     else
     {
         msg->msg_endian = BIGEND;
     }
     GUID_t readerGUID;
     GUID_t writerGUID;
     readerGUID.guidPrefix = source_guid_prefix_;
     CDRMessage::readEntityId(msg, &readerGUID.entityId);
     writerGUID.guidPrefix = dest_guid_prefix_;
     CDRMessage::readEntityId(msg, &writerGUID.entityId);
 ​
     SequenceNumberSet_t SNSet = CDRMessage::readSequenceNumberSet(msg);
     uint32_t Ackcount;
     if (!CDRMessage::readUInt32(msg, &Ackcount))
     {
         EPROSIMA_LOG_WARNING(RTPS_MSG_IN, IDSTRING "Unable to read ackcount from message");
         return false;
     }
 ​
     //Look for the correct writer to use the acknack
     for (RTPSWriter* it : associated_writers_)
     {
         bool result;
         if (it->process_acknack(writerGUID, readerGUID, Ackcount, SNSet, finalFlag, result))
         {
             if (!result)
             {
                 EPROSIMA_LOG_INFO(RTPS_MSG_IN, IDSTRING "Acknack msg to NOT stateful writer ");
             }
             return result;
         }
     }
     EPROSIMA_LOG_INFO(RTPS_MSG_IN, IDSTRING "Acknack msg to UNKNOWN writer (I looked through "
             << associated_writers_.size() << " writers in this ListenResource)");
     return false;
 }

这儿读取了几个比较重要的参数

Ackcount acknack的序列号,

SNSet 参考FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息抓包的部分,可以知道这是表示,有哪些消息已经收到,有哪些还没收到 步骤6:

 bool StatefulWriter::process_acknack(
         const GUID_t& writer_guid,
         const GUID_t& reader_guid,
         uint32_t ack_count,
         const SequenceNumberSet_t& sn_set,
         bool final_flag,
         bool& result)
 {
     std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);
     result = (m_guid == writer_guid);
 ​
     if (result)
     {
         SequenceNumber_t received_sequence_number = sn_set.empty() ? sn_set.base() : sn_set.max();
         if (received_sequence_number <= next_sequence_number())
         {
             for_matched_readers(matched_local_readers_, matched_datasharing_readers_, matched_remote_readers_,
                     [&](ReaderProxy* remote_reader)
                     {
                         if (remote_reader->guid() == reader_guid)
                         {
                             if (remote_reader->check_and_set_acknack_count(ack_count))
                             {
                                 // Sequence numbers before Base are set as Acknowledged.
                                 remote_reader->acked_changes_set(sn_set.base());
                                 if (sn_set.base() > SequenceNumber_t(0, 0))
                                 {
                                     // Prepare GAP for requested  samples that are not in history or are irrelevants.
                                     RTPSMessageGroup group(mp_RTPSParticipant, this, remote_reader->message_sender());
                                     RTPSGapBuilder gap_builder(group);
 ​
                                     if (remote_reader->requested_changes_set(sn_set, gap_builder, get_seq_num_min()))
                                     {
                                         nack_response_event_->restart_timer();
                                     }
                                     else if (!final_flag)
                                     {
                                         periodic_hb_event_->restart_timer();
                                     }
 ​
                                     gap_builder.flush();
                                 }
                                 else if (sn_set.empty() && !final_flag)
                                 {
                                     // This is the preemptive acknack.
                                     // 是否是初始化的acknack
                                     if (remote_reader->process_initial_acknack([&](ChangeForReader_t& change_reader)
                                     {
                                         assert(nullptr != change_reader.getChange());
                                         flow_controller_->add_old_sample(this, change_reader.getChange());
                                     }))
                                     {
                                         if (remote_reader->is_remote_and_reliable())
                                         {
                                             // Send heartbeat if requested
                                             send_heartbeat_to_nts(*remote_reader, false, true);
                                             periodic_hb_event_->restart_timer();
                                         }
                                     }
 ​
                                     if (remote_reader->is_local_reader() && !remote_reader->is_datasharing_reader())
                                     {
                                         intraprocess_heartbeat(remote_reader);
                                     }
                                 }
 ​
                                 // Check if all CacheChange are acknowledge, because a user could be waiting
                                 // for this, or some CacheChanges could be removed if we are VOLATILE
                                 check_acked_status();
                             }
                             return true;
                         }
 ​
                         return false;
                     }
                     );
         }
         else
         {
             print_inconsistent_acknack(writer_guid, reader_guid, sn_set.base(), received_sequence_number,
                     next_sequence_number());
         }
     }
 ​
     return result;
 }

1.ReaderProxy::check_and_set_acknack_count

acknack_count 是这个acknack message的序列号,如果这个是最新的序列号,那么将ReaderProxy中last_acknack_count设置成最新,然后处理这个acknack,如果不是最新的的序列号,直接将这个acknack忽略掉。

2.ReaderProxy::acked_changes_set

传入的参数是readerSNState的base,

acknack发送了一些消息的接受状态,readerSNState的base是这些消息中最小的SequenceNumber,SequenceNumber < base的消息状态,不会再从reader同步过来了。

根据readerSNState的base,增加或者减少changes_for_reader_ 中的消息。

3.ReaderProxy::requested_changes_set

将changes_for_reader_ 中相应的SequenceNumber的消息状态设置成REQUESTED,nack_response_event_ 重新启动

如果没找到这个SequenceNumber的消息,相当于这个消息在writer这儿没有,将这个SequenceNumber放入gap_builder,为之后构建gap消息做准备。

4.process_initial_acknack

什么是initial_acknack,可以参考17篇FastDDS 源码解析(十七)处理PDP消息——EDP匹配,就是在没有收到heartbeat的情况下发送的acknack消息

如果是本地的reader发送过来的acknack,则将所有状态为 UNACKNOWLEDGED的消息状态设置为UNSENT,然后将消息通过flow_controller_发送出去

如果是remote的reader,writer发送heartbeat给reader

5.check_acked_status

根据每个reader的changes_low_mark_,找到最小值min_low_mark,表示小于min_low_mark的消息已经被所有的reader收到了。

一些新的被所有的reader收到的消息,需要处理一下调用onWriterChangeReceivedByAll,如果消息是VOLATILE类型的,会被从history 中删除。

步骤7:

 bool check_and_set_acknack_count(
            uint32_t acknack_count)
    {
        if (last_acknack_count_ < acknack_count)
        {
            last_acknack_count_ = acknack_count;
            return true;
        }

        return false;
    }

acknack_count 是这个acknack message的序列号,

last_acknack_count_ 记录的是最新的acknack 的序列号,如果收到的acknack的序列号大于last_acknack_count_ ,则将acknack_count 赋值给last_acknack_count_,返回true。否则返回false 。

步骤8:

void ReaderProxy::acked_changes_set(
        const SequenceNumber_t& seq_num)
{
    SequenceNumber_t future_low_mark = seq_num;

    if (seq_num > changes_low_mark_)
    {
        ChangeIterator chit = find_change(seq_num, false);
        // continue advancing until next change is not acknowledged
        while (chit != changes_for_reader_.end()
                && chit->getSequenceNumber() == future_low_mark
                && chit->getStatus() == ACKNOWLEDGED)
        {
            ++chit;
            ++future_low_mark;
        }
        changes_for_reader_.erase(changes_for_reader_.begin(), chit);
    }
    else
    {
        future_low_mark = changes_low_mark_ + 1;

        if (seq_num == SequenceNumber_t() && durability_kind_ != DurabilityKind_t::VOLATILE)
        {
            // Special case. Currently only used on Builtin StatefulWriters
            // after losing lease duration, and on late joiners to set
            // changes_low_mark_ to match that of the writer.
            SequenceNumber_t min_sequence = writer_->get_seq_num_min();
            if (min_sequence != SequenceNumber_t::unknown())
            {
                SequenceNumber_t current_sequence = seq_num;
                if (seq_num < min_sequence)
                {
                    current_sequence = min_sequence;
                }
                future_low_mark = current_sequence;

                bool should_sort = false;
                for (; current_sequence <= changes_low_mark_; ++current_sequence)
                {
                    // Skip all consecutive changes already in the collection
                    ChangeConstIterator it = find_change(current_sequence);
                    while ( it != changes_for_reader_.end() &&
                            current_sequence <= changes_low_mark_ &&
                            it->getSequenceNumber() == current_sequence)
                    {
                        ++current_sequence;
                        ++it;
                    }

                    if (current_sequence <= changes_low_mark_)
                    {
                        CacheChange_t* change = nullptr;
                        if (writer_->mp_history->get_change(current_sequence, writer_->getGuid(), &change))
                        {
                            should_sort = true;
                            ChangeForReader_t cr(change);
                            cr.setStatus(UNACKNOWLEDGED);
                            changes_for_reader_.push_back(cr);
                        }
                    }
                }
                // Keep changes sorted by sequence number
                if (should_sort)
                {
                    std::sort(changes_for_reader_.begin(), changes_for_reader_.end(), ChangeForReaderCmp());
                }
            }
            else if (!is_local_reader())
            {
                future_low_mark = writer_->next_sequence_number();
            }
        }
    }
    changes_low_mark_ = future_low_mark - 1;
}

传入的参数是readerSNState的base。

acknack发送了一些消息的接受状态,readerSNState的base是这些消息中最小的SequenceNumber,SequenceNumber < base的消息状态,不会再从reader同步过来了。

ResourceLimitedVector<ChangeForReader_t, std::true_type> changes_for_reader_ 这个属性记录了消息的状态。

ReaderProxy中有一个属性changes_low_mark_ ,表示的是在这个 changes_low_mark_之前的消息,不再记录状态。

所以readerSNState的base表示的是reader 会同步消息的最小的SequenceNumber,changes_low_mark_ 表示的是本地记录状态的消息最小的SequenceNumber。

如果readerSNState的base > changes_low_mark_ , 则对于本地记录消息状态的消息,SequenceNumber从低到高遍历,如果消息是acked状态,则将消息从消息队列中移除,然后修改 changes_low_mark_

如果readerSNState的base <= changes_low_mark ,这个主要是用在builtin的statefulWriter,statefulReader上,如果有个新加入的Reader,同时durability_kind >VOLATILE(就是需要发送加入之前的所有消息),那么需要将statefulWriter中所有的消息的状态设置成UNACKNOWLEDGED,加入到 changes_for_reader_ 中去。

步骤11:

bool ReaderProxy::requested_changes_set(
        const SequenceNumberSet_t& seq_num_set,
        RTPSGapBuilder& gap_builder,
        const SequenceNumber_t& min_seq_in_history)
{
    bool isSomeoneWasSetRequested = false;

    if (SequenceNumber_t::unknown() != min_seq_in_history)
    {
        seq_num_set.for_each([&](SequenceNumber_t sit)
                {
                    ChangeIterator chit = find_change(sit, true);
                    if (chit != changes_for_reader_.end())
                    {
                        if (UNACKNOWLEDGED == chit->getStatus())
                        {
                            chit->setStatus(REQUESTED);
                            chit->markAllFragmentsAsUnsent();
                            isSomeoneWasSetRequested = true;
                        }
                    }
                    else if ((sit >= min_seq_in_history) && (sit > changes_low_mark_))
                    {
                        gap_builder.add(sit);
                    }
                });
    }

    if (isSomeoneWasSetRequested)
    {
        EPROSIMA_LOG_INFO(RTPS_READER_PROXY, "Requested Changes: " << seq_num_set);
    }

    return isSomeoneWasSetRequested;
}

传入的参数是sn_set,就是acknack中 请求的消息的 SequenceNumber

将changes_for_reader_ 中相应的SequenceNumber的消息状态设置成REQUESTED

如果没找到这个SequenceNumber的消息,相当于这个消息在writer这儿没有,将这个SequenceNumber放入gap_builder

我们知道gap消息是writer发送给reader的消息,标识HistoryCache中的一些Change不再可用,也不会再发给Reader。

这个gap_builder就是构建这个gap消息的。

步骤12:

void StatefulWriter::check_acked_status()
{
    std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);

    bool all_acked = true;
    bool has_min_low_mark = false;
    // #8945 If no readers matched, notify all old changes.
    SequenceNumber_t min_low_mark = mp_history->next_sequence_number() - 1;

    //根据每个reader的changes_low_mark_,找到最小值min_low_mark,表示小于min_low_mark的消息已经被所有的reader收到了
    for_matched_readers(matched_local_readers_, matched_datasharing_readers_, matched_remote_readers_,
            [&all_acked, &has_min_low_mark, &min_low_mark](ReaderProxy* reader)
            {
                //changes_low_mark_  对一个readerproxy来说,seqnumber <changes_low_mark_的消息都已经acknowledged了
                SequenceNumber_t reader_low_mark = reader->changes_low_mark();
                if (reader_low_mark < min_low_mark || !has_min_low_mark)
                {
                    has_min_low_mark = true;
                    min_low_mark = reader_low_mark;
                }

                if (reader->has_changes())
                {
                    all_acked = false;
                }

                return false;
            }
            );

    bool something_changed = all_acked;
    SequenceNumber_t min_seq = get_seq_num_min();
    if (min_seq != SequenceNumber_t::unknown())
    {
        // In the case where we haven't received an acknack from a recently matched reader,
        // min_low_mark will be zero, and no change will be notified as received by all
        if (next_all_acked_notify_sequence_ <= min_low_mark)
        {
            if ((mp_listener != nullptr) && (min_low_mark >= get_seq_num_min()))
            {
                // We will inform backwards about the changes received by all readers, starting
                // on min_low_mark down until next_all_acked_notify_sequence_. This way we can
                // safely proceed with the traversal, in case a change is removed from the history
                // inside the callback
                History::iterator history_end = mp_history->changesEnd();
                History::iterator cit =
                        std::lower_bound(mp_history->changesBegin(), history_end, min_low_mark,
                                [](
                                    const CacheChange_t* change,
                                    const SequenceNumber_t& seq)
                                {
                                    return change->sequenceNumber < seq;
                                });
                if (cit != history_end && (*cit)->sequenceNumber == min_low_mark)
                {
                    ++cit;
                }

                SequenceNumber_t seq{};
                SequenceNumber_t end_seq = min_seq > next_all_acked_notify_sequence_ ?
                        min_seq : next_all_acked_notify_sequence_;

                // The iterator starts pointing to the change inmediately after min_low_mark
                --cit;

                do
                {
                    // Avoid notifying changes before next_all_acked_notify_sequence_
                    CacheChange_t* change = *cit;
                    seq = change->sequenceNumber;
                    if (seq < next_all_acked_notify_sequence_)
                    {
                        break;
                    }

                    // Change iterator before it possibly becomes invalidated
                    if (cit != mp_history->changesBegin())
                    {
                        --cit;
                    }

                    // Notify reception of change (may remove that change on VOLATILE writers)
                    mp_listener->onWriterChangeReceivedByAll(this, change);

                    // Stop if we got to either next_all_acked_notify_sequence_ or the first change
                } while (seq > end_seq);
            }

            next_all_acked_notify_sequence_ = min_low_mark + 1;
        }

        if (min_low_mark >= get_seq_num_min())
        {
            may_remove_change_ = 1;
        }

        min_readers_low_mark_ = min_low_mark;
        something_changed = true;
    }

    if (all_acked)
    {
        std::unique_lock<std::mutex> all_acked_lock(all_acked_mutex_);
        SequenceNumber_t next_seq = mp_history->next_sequence_number();
        next_all_acked_notify_sequence_ = next_seq;
        min_readers_low_mark_ = next_seq - 1;
        all_acked_ = true;
        all_acked_cond_.notify_all();
    }

    if (something_changed)
    {
        may_remove_change_cond_.notify_one();
    }
}

根据每个reader的changes_low_mark_,找到最小值min_low_mark,表示小于min_low_mark的消息已经被所有的reader收到了。

一些新的被所有的reader收到的消息,需要处理一下调用onWriterChangeReceivedByAll,如果消息是VOLATILE类型的,会被从history 中删除。

步骤10 这边详细介绍一下

nack_response_event_ = new TimedEvent(
        pimpl->getEventResource(),
        [&]() -> bool
        {
            perform_nack_response();
            return false;
        },
        TimeConv::Time_t2MilliSecondsDouble(m_times.nackResponseDelay));

这个可以参考 第6篇 车载消息中间件FastDDS 源码解析(六)BuiltinProtocols(中)EDP,这个TimedEvent是在StatefulWriter初始化的时候初始化的。当收到acknack消息之后就会启动这个nack_response_event_,响应时间默认是5ms

void StatefulWriter::perform_nack_response()
{
    std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);

    uint32_t changes_to_resend = 0;
    for (ReaderProxy* reader : matched_remote_readers_)
    {
        changes_to_resend += reader->perform_acknack_response([&](ChangeForReader_t& change)
                        {
                            // This labmda is called if the ChangeForReader_t pass from REQUESTED to UNSENT.
                            assert(nullptr != change.getChange());
                            flow_controller_->add_old_sample(this, change.getChange());
                        }
                        );
    }

    lock.unlock();

    // Notify the statistics module
    on_resent_data(changes_to_resend);
}
uint32_t ReaderProxy::perform_acknack_response(
        const std::function<void(ChangeForReader_t& change)>& func)
{
    return convert_status_on_all_changes(REQUESTED, UNSENT, func);
}

uint32_t ReaderProxy::convert_status_on_all_changes(
        ChangeForReaderStatus_t previous,
        ChangeForReaderStatus_t next,
        const std::function<void(ChangeForReader_t& change)>& func)
{
    assert(previous > next);

    // NOTE: This is only called for REQUESTED=>UNSENT (acknack response) or
    //       UNDERWAY=>UNACKNOWLEDGED (nack supression)

    uint32_t changed = 0;
    for (ChangeForReader_t& change : changes_for_reader_)
    {
        if (change.getStatus() == previous)
        {
            ++changed;
            change.setStatus(next);

            if (func)
            {
                func(change);
            }
        }
    }

    return changed;
}

这两个函数结合起来一起看,扫描所有的远端的reader,

将reader中message状态为REQUESTED的消息调用flow_controller_->add_old_sample,准备重新发送。同时将message状态为REQUESTED的消息的状态设置为UNSENT。

2.ChangeForReader_t的状态

classDiagram
      StatefulWriter *-- ReaderProxy
      StatefulWriter *-- periodic_hb_event_
      StatefulWriter *-- nack_response_event_
      ReaderProxy *-- intitial_heartbeat_event_
      ReaderProxy *-- nack_supression_event_
      
      class StatefulWriter{
      		+ResourceLimitedVector<ReaderProxy*> matched_local_readers_
      		+ResourceLimitedVector<ReaderProxy*> matched_datasharing_readers_
      		+ResourceLimitedVector<ReaderProxy*> matched_remote_readers_
      		TimedEvent* periodic_hb_event_
      		TimedEvent* nack_response_event_
      }
      class ReaderProxy{
      		+TimedEvent* intitial_heartbeat_event_
      		+TimedEvent* nack_supression_event_
      		+ResourceLimitedVector<ChangeForReader_t, std::true_type> changes_for_reader_
      }

StatefulWriter有3个队列存放了和这个StatefulWriter对应的reader的信息,也就是这个reader的代理,ReaderProxy。

ReaderProxy中保存了一个队列,保存了各个消息的状态。然后根据这些消息的状态选择重发。

 enum ChangeForReaderStatus_t
 ​
 {
 ​
     UNSENT = 0,                    //!< UNSENT
 ​
     REQUESTED = 1,                 //!< REQUESTED
 ​
     UNACKNOWLEDGED = 2,            //!< UNACKNOWLEDGED
 ​
     ACKNOWLEDGED = 3,              //!< ACKNOWLEDGED
 ​
     UNDERWAY = 4                   //!< UNDERWAY
 ​
 };

在Writer这儿,一个消息的状态一共有5种。

UNSENT 就是还没发送,这是消息的初始状态

REQUESTED 是请求状态, 当收到acknack消息,被reader请求的消息,会被设置成REQUESTED

UNACKNOWLEDGED 是没有被reader收到

ACKNOWLEDGED 已经发送给reader,同时reader已经收到

UNDERWAY 已经发送给reader,但是还没有收到reader的acknack消息

第一篇 一个例子

车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用

第二篇fastdds的组成

车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)

车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)

车载消息中间件FastDDS 源码解析(四)RtpsParticipant的创建(下)

车载消息中间件FastDDS 源码解析(五)BuiltinProtocols(上)

车载消息中间件FastDDS 源码解析(六)BuiltinProtocols(中)EDP

车载消息中间件FastDDS 源码解析(七)BuiltinProtocols(下)WLP&TypeLookupManager

车载消息中间件FastDDS 源码解析(八)TimedEvent

车载消息中间件FastDDS 源码解析(九)Message