跳转至

交易所协议分层与序列一致性

1.协议分层 会话层:登录、心跳、重连、序列号维护、重传协商。 业务层:订单簿增量、成交、状态事件、快照事件。 编解码层:字节序转换、字段校验、结构体映射。

#include <cstdint>
#include <optional>
#include
#include <stdexcept>
#include <vector>

enum class SessionMsgType : uint8_t { Logon, Heartbeat, Logout, ReplayRequest };
enum class BizMsgType : uint8_t { Add, Modify, Cancel, Trade, Snapshot };

struct SessionHeader {
  uint64_t seq_num;
  SessionMsgType type;
};

struct BizHeader {
  uint64_t seq_num;
  BizMsgType type;
  uint32_t symbol_id;
};

struct DecodedPacket {
  SessionHeader session;
  BizHeader biz;
  std::span<const std::byte> payload;
};

class Decoder final {
 public:
  [[nodiscard]] static std::optional<DecodedPacket> decode(
      std::span<const std::byte> bytes) noexcept {
    if (bytes.size() < 32) return std::nullopt;
    // 示例:实际项目中应进行协议版本、字段边界、CRC/校验和校验。
    return DecodedPacket{
        .session =
            SessionHeader{.seq_num = 0, .type = SessionMsgType::Heartbeat},
        .biz =
            BizHeader{
                .seq_num = 0, .type = BizMsgType::Snapshot, .symbol_id = 0},
        .payload = bytes.subspan(32)};
  }
};

2.序列一致性处理 每路行情流维护 last_seq,严格检查连续性。 检测到 gap 后进入恢复态:请求重传、合并回放、再切回实时流。 恢复完成前禁止策略继续消费该标的的实时增量。

#include <cstdint>
#include <queue>
#include <stdexcept>

class SeqGate final {
 public:
  enum class State : uint8_t { Live, Recovering };

  explicit SeqGate(uint64_t start_seq = 0)
      : last_seq_(start_seq), state_(State::Live) {}

  [[nodiscard]] bool on_live_packet(uint64_t seq) noexcept {
    if (state_ == State::Recovering) {
      // 恢复态期间实时包只缓存不放行(这里简化为直接拒绝)。
      return false;
    }
    if (seq == last_seq_ + 1) {
      last_seq_ = seq;
      return true;
    }
    if (seq > last_seq_ + 1) {
      state_ = State::Recovering;
      missing_begin_ = last_seq_ + 1;
      missing_end_ = seq - 1;
    }
    return false;
  }

  void on_replay_packet(uint64_t seq) {
    if (state_ != State::Recovering) return;
    if (seq != last_seq_ + 1) {
      throw std::runtime_error("replay packet out-of-order");
    }
    last_seq_ = seq;
    if (last_seq_ == missing_end_) {
      state_ = State::Live;
      missing_begin_ = missing_end_ = 0;
    }
  }

  [[nodiscard]] State state() const noexcept { return state_; }
  [[nodiscard]] uint64_t last_seq() const noexcept { return last_seq_; }
  [[nodiscard]] bool can_trade() const noexcept {
    return state_ == State::Live;
  }

 private:
  uint64_t last_seq_{0};
  uint64_t missing_begin_{0};
  uint64_t missing_end_{0};
  State state_{State::Live};
};

3.时间戳分层 exchange_ts:交易所时间。 nic_rx_ts:网卡接收硬件时间。 app_ts:应用层处理时间。

#include <chrono>
#include <cstdint>

struct TimeTriple {
  uint64_t exchange_ts_ns;  // 交易所报文携带时间戳(ns)
  uint64_t nic_rx_ts_ns;    // NIC 硬件时间戳(ns)
  uint64_t app_ts_ns;       // 应用处理时间戳(ns)
};

[[nodiscard]] inline uint64_t now_ns() noexcept {
  return static_cast<uint64_t>(
      std::chrono::duration_cast<std::chrono::nanoseconds>(
          std::chrono::steady_clock::now().time_since_epoch())
          .count());
}

[[nodiscard]] inline int64_t wire_to_app_latency_ns(
    const TimeTriple& t) noexcept {
  return static_cast<int64_t>(t.app_ts_ns) -
         static_cast<int64_t>(t.nic_rx_ts_ns);
}

[[nodiscard]] inline int64_t exch_to_nic_latency_ns(
    const TimeTriple& t) noexcept {
  return static_cast<int64_t>(t.nic_rx_ts_ns) -
         static_cast<int64_t>(t.exchange_ts_ns);
}