1. DoIP实体激活与状态机

任务目标

实现一个DoIP实体的激活状态机,覆盖从监听、收到激活请求、执行激活到激活完成的完整流程,并处理激活过程中的超时与失败回退。本案例聚焦于DoIP实体激活的核心状态转换逻辑,不涉及完整TCP/TLS传输层实现。

状态定义

状态含义进入条件超时时间
LISTENING等待客户端激活请求实体启动—
ACTIVATION_PENDING已收到激活请求,等待处理完成收到有效激活请求2s
ACTIVE激活完成,可处理DoIP消息激活处理成功—
INACTIVE激活失败或超时后的回退状态超时/处理失败—

核心实现

#include <cstdint>
#include <functional>
#include <chrono>
#include <stdexcept>

enum class DoIPState : uint8_t {
    LISTENING,
    ACTIVATION_PENDING,
    ACTIVE,
    INACTIVE
};

enum class ActivationResult : uint8_t {
    SUCCESS,
    FAILURE,
    TIMEOUT
};

class DoIPEntityActivator {
public:
    using Clock = std::chrono::steady_clock;
    using TimePoint = Clock::time_point;

    explicit DoIPEntityActivator(std::function<bool()> activation_handler)
        : activation_handler_(std::move(activation_handler)),
          state_(DoIPState::LISTENING),
          pending_since_(TimePoint{}) {}

    // 收到客户端激活请求时调用
    void onActivationRequest() {
        if (state_ != DoIPState::LISTENING) {
            return;  // 非监听状态忽略新请求
        }
        state_ = DoIPState::ACTIVATION_PENDING;
        pending_since_ = Clock::now();
    }

    // 周期性调用,驱动状态机推进
    void tick() {
        if (state_ != DoIPState::ACTIVATION_PENDING) {
            return;
        }

        auto elapsed = Clock::now() - pending_since_;
        if (elapsed > std::chrono::seconds(2)) {
            state_ = DoIPState::INACTIVE;
            return;
        }

        // 尝试执行激活处理
        bool success = false;
        try {
            success = activation_handler_();
        } catch (...) {
            success = false;
        }

        if (success) {
            state_ = DoIPState::ACTIVE;
        } else {
            state_ = DoIPState::INACTIVE;
        }
    }

    // 外部主动重置实体(如收到关闭连接)
    void reset() {
        state_ = DoIPState::LISTENING;
        pending_since_ = TimePoint{};
    }

    DoIPState getState() const { return state_; }

    // 获取当前状态对应的激活结果(仅对终态有意义)
    ActivationResult getActivationResult() const {
        switch (state_) {
            case DoIPState::ACTIVE:   return ActivationResult::SUCCESS;
            case DoIPState::INACTIVE: return ActivationResult::FAILURE;
            default: throw std::logic_error("Not in terminal state");
        }
    }

private:
    std::function<bool()> activation_handler_;
    DoIPState state_;
    TimePoint pending_since_;
};

验证方法

编写测试代码,依次验证以下场景:

  1. 正常激活:activation_handler返回true,调用onActivationRequest后立即tick,状态应为ACTIVE。
  2. 激活失败:activation_handler返回false,调用onActivationRequest后立即tick,状态应为INACTIVE。
  3. 超时回退:activation_handler内部阻塞超过2秒(或使用模拟时钟推进),状态应变为INACTIVE。
  4. 非监听状态忽略:在ACTIVE状态下再次调用onActivationRequest,状态不应改变。

通过条件:上述四个场景的状态转换结果与预期完全一致,且无异常抛出。

关键说明

  • 激活处理函数由外部注入,本实现不关心具体激活逻辑(如TLS证书校验、路由表配置等),只负责状态编排与超时控制。
  • 超时检测采用轮询方式(tick),实际工程中可替换为事件驱动或定时器回调,但状态转换逻辑不变。
  • INACTIVE为终态,需通过reset()才能回到LISTENING,模拟DoIP实体重新初始化。