Buffer——缓冲区有什么

Buffer 回答的问题是:「收发的字节先存哪?」 它被逼出来的原因是「TCP 是流式协议,一次收不到整条消息」。这一篇讲它有什么——职责、内部结构、边界、异常、形态。注意:Buffer 是无状态工具,不是有状态组件。


一、它解决什么问题

TCP 是流式协议,不是消息协议:

1
2
3
4
一次 recv 可能收到:
→ 半条消息(消息还没发完)
→ 一条半消息(两条粘在一起)
→ 恰好一条(运气好)

调用者不能假设「一次 recv = 一条消息」。需要一个地方先把字节攒起来,攒够一条消息再处理。这就是 Buffer 被逼出来的原因。

1
2
接收:字节先存进 Buffer,攒够一条消息再取出处理
发送:待发的数据先排进 Buffer,再逐步写出

二、它有什么(内部结构)

Buffer 是「数据 + 算法 + 接口」,但无状态

1
2
3
4
5
6
7
8
9
10
11
12
13
class Buffer {
// —— 数据 ——
std::vector<char> data_; // 字节存储
size_t read_index_; // 读指针
size_t write_index_; // 写指针

public:
// —— 接口 ——
void append(const char* p, size_t n); // 写入字节
size_t readable() const; // 可读字节数
void retrieve(size_t n); // 已读,丢弃
const char* peek() const; // 看当前可读数据
};
1
2
3
数据:字节数组 + 读指针 + 写指针
算法:写入(append)、读出(peek/retrieve)、扩容
接口:append / readable / peek / retrieve

核心操作

1
2
3
append(bytes)     ← 从网络收进来的字节,先 append 进 Buffer
peek() ← 看「现在攒了多少、够不够一条消息」
retrieve(n) ← 攒够一条消息,取出处理,指针前移

三、它的边界:只管「暂存」,不管「内容」

1
2
3
✅ 管:字节的暂存、读写指针、扩容
❌ 不管:字节是什么消息(解析层的事)
❌ 不管:连接状态(Connection/Session 的事)
1
2
3
Buffer 存了一堆字节
→ 它不知道这是「登录消息」还是「心跳」
→ 它只知道「这里有 N 个字节可读」

Buffer 是纯粹的「字节容器」——存进去、读出来,仅此而已。


四、它的形态:无状态工具,函数导出

Buffer 和有状态组件(EventLoop/Connection/Session)本质不同:

1
2
3
4
5
无状态:Buffer 不持有「跨调用的连接状态」
→ 它的状态(字节数组、指针)就是它的数据本身
→ 不需要初始化,不管理生命周期

被调用才操作:被 append / peek / retrieve 时才动

所以它是无状态工具——「数据结构 + 算法 + 接口」,但没有生命周期、不需要类封装的那套「构造/析构/start/stop」。通常一个 Buffer 直接内嵌在 Session 里用:

1
2
3
4
5
struct Session {
Buffer recv_buf; // 接收缓冲,直接是 Session 的一个字段
Buffer send_buf; // 发送缓冲
...
};

五、它的异常

1
2
3
缓冲区满:
写入速度超过处理速度,Buffer 塞满
→ 处理:丢弃数据、限流、记录日志、或断开连接

Buffer 的异常很少,因为它的职责很窄——它就是「暂存」,唯一的异常就是「存不下了」。


六、它和其他组件的关系

1
2
3
Buffer ← 内嵌在 Session 里(recv_buf / send_buf)
Buffer ← 被 EventLoop 间接操作(可读 → append;可写 → retrieve 发送)
Buffer 不主动依赖任何组件——它是被用的「工具」
1
2
EventLoop ──可读──→ Session ──append──→ Buffer(收)
EventLoop ──可写──→ Session ──retrieve→ Buffer(发)

Buffer 是网络系统里最「被动」的东西——没有自己的控制流,没有生命周期,谁用谁操作。


七、小结

1
2
3
4
5
6
7
8
9
Buffer 有什么:
职责:字节暂存(收进来、发出去)
结构:字节数组 + 读指针 + 写指针
接口:append / peek / retrieve / readable
边界:只管「暂存」,不管「内容」
形态:无状态工具,函数导出,内嵌在 Session 里
异常:缓冲区满

一句话:Buffer 是「字节的暂存箱」,被读写时才动,没有自己的生命周期。