消息缓冲区 MsgBuffer
第 2 课:消息缓冲区 MsgBuffer 对应源文件: trantor/utils/MsgBuffer.h / MsgBuffer.cc — 核心读写缓冲区 trantor/net/inner/BufferNode.h — 发送队列多态节点 一、为什么需要 MsgBuffer? TCP 是流式协议,recv() 一次调用不一定能读完一个完整消息,也可能读到多个消息粘在一起(粘包)。 需要一个弹性缓冲区来: 接收数据时:把内核 socket 缓冲区的数据读进来,等凑够一个完整包再交给上层 发送数据时:把待发送数据先攒在缓冲区,等 socket 可写时分批发出 支持在头部预留空间(prepend),方便后填消息长度字段 二、内存布局 2.1 物理结构 1 2 3 4 5 6 7 8 9 buffer_ (std::vector<char>,初始大小 = 2048 + 8) 索引: 0 8 tail_ buffer_.size() │ │ │ │ ▼ ▼ ▼ ▼ [prepend区][─── 可读数据 ───][──── 可写空间 ────] └── 8字节 ┘ ↑ ↑ head_ tail_ prepend 区 [0, head_):保留 8 字节,用于在数据头部插入字段(不需要移动数据) 可读区 [head_, tail_):已接收但未被消费的数据,大小 = tail_ - head_ 可写区 [tail_, buffer_.size()):空闲空间,大小 = buffer_.size() - tail_ 2.2 关键常量与初始状态 1 2 3 4 5 6 7 8 9 // MsgBuffer.cc 第 31 行 static constexpr size_t kBufferOffset{8}; // prepend 预留大小 // 构造函数(MsgBuffer.cc 第 34-37 行) MsgBuffer::MsgBuffer(size_t len) : head_(kBufferOffset), // head_ 从 8 开始 initCap_(len), // 记录初始容量,用于 retrieveAll 的缩容 buffer_(len + head_), // 总容量 = 用户要求 + 8字节 prepend tail_(head_) // tail_ 也从 8 开始,初始可读字节为 0 初始状态(len = 2048): ...