Buffer 设计核心思想

应用层非阻塞 socket 收发缓冲区,解决非阻塞 IO 下的数据粘包、半包问题。通过动态内存管理和读写指针索引实现高效数据存取。

核心成员变量与常量

  • std::vector<char> _buffer:动态内存容器,自动管理缓冲区内存
  • size_t _reader_idx:读位置索引,标记已读取数据的起始位置
  • size_t _writer_idx:写位置索引,标记已写入数据的结束位置
  • const static int kInitialSize = 1024:默认缓冲区初始大小
  • const static int kCheapPrepend = 8:头部预留空间大小,用于协议头等场景

主要接口功能解析

数据读取接口

const char *peek() const
返回当前可读数据的起始指针,不移动读索引

size_t readableBytes() const
返回当前可读数据的总字节数,计算公式为:
_writer_idx - _reader_idx

std::string retrieveAsString(size_t len)
提取指定长度的数据并转为字符串,同时移动读索引

数据写入接口

char *beginWrite()
返回当前可写区域的起始指针

void append(const void *data, size_t len)
追加数据到缓冲区末尾,自动处理扩容

void ensureWritableBytes(size_t len)
确保缓冲区有足够可写空间,不足时触发扩容

特殊功能接口

ssize_t readFd(int fd, int *savedErrno)
从文件描述符读取数据到缓冲区,处理 EAGAIN 等非阻塞场景

std::optional<std::string> getline()
按行提取数据,使用 C++17 optional 安全返回

内存管理策略

void makeSpace(size_t len)
核心扩容算法:

  1. 检查当前空闲空间(前置空间 + 尾部空间)是否足够
  2. 如果足够,移动数据到缓冲区头部
  3. 如果不足,触发 vector 扩容

移动数据条件:
(prependableBytes() + writableBytes()) < (len + kCheapPrepend)

性能优化点

  • 减少内存拷贝:通过移动数据而非重新分配
  • 预留空间:头部预留 8 字节避免频繁移动
  • 批量操作:支持大块数据一次性处理
  • 零拷贝接口:直接暴露指针给上层

典型使用场景

Buffer buf;
// 读取数据
ssize_t n = buf.readFd(sockfd, &errno);
if(n > 0) {
    // 处理一行数据
    auto line = buf.getline();
    if(line) {
        process(*line);
    }
}
// 发送数据
buf.append("response", 8);
send(buf.peek(), buf.readableBytes());

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐