AltasProxy:Buffer 与从 fd 读数据

本章讲解为什么要设计buffer和他的作用

  1. 在网络编程的应用层中必须使用 Buffer(缓冲区),核心原因是底层 IO 读取数据的粒度不受控制 —— 调用 read ()/recv () 读取 socket 数据时,实际读取的字节数由内核、网络状况、对方发送策略共同决定,可能出现 “半包”(仅读到半行数据)或 “粘包”(一次读到多行数据)的情况,而协议解析(如按 \r\n 分割、按长度解析)需要完整的数据包,若没有 Buffer,直接用 read () 的原始结果解析会因数据不完整或混乱导致失败。因此应用层 Buffer 的核心作用是将 “接收数据” 和 “按协议解析数据” 解耦:读操作仅负责把文件描述符(fd)中的数据搬运到 Buffer 中暂存,解析操作则在这块内存中查找 \r\n、计算长度以提取完整数据包;若没有 Buffer,不仅无法处理半包(半行数据无暂存位置,下次读取会丢失)和粘包(多行数据被当成一行解析)问题,还会导致 “读数据” 与 “解析数据” 强耦合,代码混乱且难以维护,所以必须通过应用层 Buffer 将碎片化的读取数据合成完整的一段后再进行解析。

  2. 用readerIndex和writerIndex同时把一块内存分成三段,prependable:[0, readerIndex),前面已经「读掉」的空位,可以拿来在前面再写一点(例如长度头)。readable:[readerIndex, writerIndex),还没被业务消费的数据,peek() 看这里,retrieve(len) 把 readerIndex 往后挪。writable:[writerIndex, size()),还能写的位置,append 写这里并推进 writerIndex。

  3. 要写的数据比当前 writable 多时:先把 readable 整段挪到 buffer 最前面(利用 prependable 空位),空出后面一大块 writable,避免频繁 realloc。挪完还是不够,就 resize 把 buffer 拉长。这样既省拷贝次数,又能在真正需要时扩容。

  4. 前面固定留 8 字节(kCheapPrepend),方便以后在消息前面写长度头之类,不用把整段数据往后挪,所以叫「cheap
    prepend」。

[ prependable ][ readable ][ writable ]
^ ^ ^ ^
0 readerIndex writerIndex size()

posted on 2026-03-02 16:10  cyusouyiku  阅读(0)  评论(0)    收藏  举报