本系列主要旨在帮助初学者学习和巩固 Linux 高性能网络编程,同时记录笔者在学习与手写 muduo 网络库项目过程中的心得体会。
本系列会围绕 muduo 网络库的核心思想展开,包括 Reactor 模式、事件循环、Channel、Poller、TcpServer、TcpConnection、Buffer、线程池等内容。

个人主页: 爱装代码的小瓶子
文章系列: Linux
2. C++
3. muduo 网络库项目
文章目录
- [1. buffer模块的成员:](#1. buffer模块的成员:)
-
- [1.1 构造函数和简单功能的实现:](#1.1 构造函数和简单功能的实现:)
- [1.2 将读写的位置进行偏移:](#1.2 将读写的位置进行偏移:)
- [1.3 读取类函数:](#1.3 读取类函数:)
- [1.4 写入类函数:](#1.4 写入类函数:)
- [1.5 一些为了方便调用的函数:](#1.5 一些为了方便调用的函数:)
- 总结:
1. buffer模块的成员:
cpp
private:
std::vector<char> _buffer;
uint64_t _reader_index; // 读位置的偏移量
uint64_t _writer_index; // 写位置偏移量
为什么选择使用 vector<char>作为底层呢!,这是因为:
因为网络收发本质是"字节流",char 最适合表示一个字节;vector<char> 又能提供连续内存、自动扩容、RAII 管理,所以 muduo 用它做底层 Buffer。
同时我们还需要提供读和写两个偏移量。你可能现在不太清楚,但是后面的操作很快就能理解
1.1 构造函数和简单功能的实现:
我们来看看怎么写构造函数和一些简单功能:
cpp
Buffer() : _buffer(BUFFER_DEFAULT_SIZE), _reader_index(0), _writer_index(0) {}
char *Begin() { return _buffer.data(); }
// 1. 获取写入读取的地址
char *WritePosition() { return Begin() + _writer_index; }
char *ReadPosition() { return Begin() + _reader_index; }
// 2. 获取尾部和头部的空间和可读空间
uint64_t GetTailSpace() { return _buffer.size() - _writer_index; }
uint64_t GetHeadSpace() { return _reader_index; }
uint64_t GetReadabeSpace() { return _writer_index - _reader_index; }
来着重讲一下可读空间,其实本质就是吧写的偏移量减去读的偏移量,这些便是我们还可以读取的区域。
1.2 将读写的位置进行偏移:
cpp
// 3. 将读写位置的下标进行偏移
void MoveReadOffset(uint64_t len)
{
if (len == 0)
return;
assert(len <= GetReadabeSpace());
_reader_index += len;
if (_reader_index == _writer_index)
{
_reader_index = 0;
_writer_index = 0;
}
}
void MoveWriteoffset(uint64_t len)
{
if (len == 0)
return;
assert(len <= GetTailSpace());
_writer_index += len;
}
在移动读的坐标的时候,需要确保读的偏移量不能大于写的偏移量。所以这里我们需要断言,如果相等就同时清除成为0.
这里这个也很简单,还是比较容易的。
1.3 读取类函数:
cpp
// 4. 读取:
void Read(void *buf, uint64_t len)
{
assert(len <= GetReadabeSpace());
std::copy(ReadPosition(), ReadPosition() + len, (char *)buf);
}
void ReadAndPop(void *buf, uint64_t len)
{
Read(buf, len);
MoveReadOffset(len);
}
std::string ReadString(uint64_t len)
{
if (len == 0)
return "";
assert(len <= GetReadabeSpace());
std::string ret;
ret.resize(len);
Read(&ret[0], len);
return ret;
}
std::string ReadStringPop(uint64_t len)
{
std::string str = ReadString(len);
MoveReadOffset(len);
return str;
}
先提供普通的read函数,就是把我们的Buffer中的指定内容拷贝一下进入buf,这个buf就是输出型函数。这个就是后面函数实现的基础:
- 读取之后还需要移动下标,结合两个基础函数完成。
- 像读取字符串情况下读取,并且是返回了字符串,其中最重要的是先设置大小,随后通过read写入,所以是
Read(&ret[0], len);,其中&ret[0]为什么不是ret.c_str(),本质是因为:ret.c_str()是常量,不可以进行修改。而&ret[0]可以拿到字符串内部可写缓冲区的首地址。 - 读取并且改变小标,同样调用第二个函数和moveReadOffset就可以了。
1.4 写入类函数:
cpp
void EnsureWriteSpace(uint64_t len)
{
if (len <= GetTailSpace())
return;
if (len <= GetTailSpace() + GetHeadSpace())
{
uint64_t rsz = GetReadabeSpace();
std::copy(ReadPosition(), WritePosition(), _buffer.begin());
_reader_index = 0;
_writer_index = rsz;
}
else
{
_buffer.resize(_buffer.size() + len);
}
}
这个是为了下面的写做准备的,需要确保写的区域够用,分三种情况来看:
- 如果尾部空间够用就直返回,完全不需要扩容
- 如果头部加尾部够用,进行移动,移动至开头,同时下标需要调整
- 如果都不够的话,就直接进行扩容,大小为原本大小 + size;
下面就是写入函数:
cpp
// 4.5 写入:
void Write(const void *data, uint64_t len)
{
if (len == 0)
return;
EnsureWriteSpace(len);
const char *d = (const char *)data;
std::copy(d, d + len, WritePosition());
}
void WriteAndPush(const void *data, uint64_t len)
{
Write(data, len);
MoveWriteoffset(len);
}
void WriteString(std::string data) { Write(&data[0], data.size()); }
void WriteBuffer(Buffer &data) { Write(data.ReadPosition(), data.GetReadabeSpace()); }
void WriteStringAndPush(std::string data)
{
Write(&data[0], data.size());
MoveWriteoffset(data.size());
}
void WriteBufferPush(Buffer &data)
{
WriteBuffer(data);
MoveWriteoffset(data.GetReadabeSpace());
}
第一个就是正常的拷贝进入_buffer里面,将其拷贝到写的下标之后,这个也是下面写的基础,这里没有移动的下标,只是单独的写入,将其拷贝到我们的buffer里面。
void WriteAndPush(const void *data, uint64_t len)这个就是写入的时候,还需要移动下标,直接调用MoveWriteoffset(len);可以了。- 随后两个是写入字符串,和写入缓冲区,就是缓冲区的元素直接写入就好了,还是比较简单的。
- 剩下的就是写入并且下标也会移动。
1.5 一些为了方便调用的函数:
上面的读写函数已经可以完成基本操作了,但是在网络编程中,我们经常还会遇到一些更具体的需求。
比如:
- 从缓冲区中读取一行数据。
- 判断当前缓冲区里面有没有完整的一行。
- 使用完之后清理缓冲区。
所以这里再额外提供几个比较方便调用的函数:
cpp
char *FindCRFL() { return (char *)memchr(ReadPosition(), '\n', GetReadabeSpace()); }
std::string GetLine()
{
char *pos = FindCRFL();
if (pos == nullptr)
return "";
return ReadString(pos - ReadPosition() + 1); // 希望这个\n也出现在里面
}
std::string GetLineAndPop()
{
std::string str = GetLine();
MoveReadOffset(str.size());
return str;
}
// 5 清理内存:
void Cleer()
{
_reader_index = 0;
_writer_index = 0;
}
我们来一个一个看:
-
char *FindCRFL()这个函数的作用就是:从当前可读区域里面查找
\n。cppmemchr(ReadPosition(), '\n', GetReadabeSpace());这里的意思就是,从
ReadPosition()开始,在GetReadabeSpace()这么长的范围里面,查找字符\n。为什么是找
\n呢?这是因为很多网络协议里面,一行数据通常是以换行结尾的,比如 HTTP 中常见的\r\n。这里只要找到了\n,基本就可以说明当前 Buffer 里面已经有一整行数据了。如果找到了,就返回这个
\n的地址;如果没找到,就返回nullptr。 -
std::string GetLine()这个函数的作用就是:获取一行数据,但是不移动读下标。
首先调用
FindCRFL()找到换行符的位置:cppchar *pos = FindCRFL();如果找不到,说明现在缓冲区里面还没有完整的一行,所以直接返回空字符串:
cppif (pos == nullptr) return "";如果找到了,就说明可以读取一行了:
cppreturn ReadString(pos - ReadPosition() + 1);这里
pos - ReadPosition()算出来的是从读位置到\n之前的长度,但是我们希望把\n也读取出来,所以需要+ 1。也就是说,这个函数返回的字符串里面是包含换行符
\n的。 -
std::string GetLineAndPop()这个函数就是在
GetLine()的基础上,再把读下标往后移动。cppstd::string str = GetLine(); MoveReadOffset(str.size()); return str;所以它的逻辑也很简单:
- 先读取一行数据。
- 再根据这一行的长度移动读下标。
- 最后返回这一行数据。
这样这行数据就相当于从 Buffer 中被"取走"了,下次读取的时候就不会再读到这一行了。
-
void Cleer()这个函数的作用就是清空缓冲区。
注意这里并不是真的把
_buffer里面的每个字符都清掉,而是直接把读写下标都设置为 0:cpp_reader_index = 0; _writer_index = 0;因为对于 Buffer 来说,真正有效的数据范围是
_reader_index到_writer_index之间。只要把这两个下标归零,就表示当前没有任何可读数据了。这种做法比真的清空数组更加高效。
最后注意一下,这里的函数名
FindCRFL和Cleer可能是我的之前的拼写问题,一般更常见的写法是FindCRLF和Clear。
总结:
Buffer模块核心思想:
Buffer本质上就是一块连续的内存,再配合两个下标来管理数据。
一个是 _reader_index,表示当前读到哪里了;一个是 _writer_index,表示当前写到哪里了。
所以整个 Buffer 的核心就是:
- 写数据的时候,从
_writer_index开始写。 - 读数据的时候,从
_reader_index开始读。 - 读完之后移动
_reader_index。 - 写完之后移动
_writer_index。 - 如果两个下标相等,说明数据都被读完了,就可以一起归零。
#mermaid-svg-k8jkU7ZEhWrSHi9p{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-k8jkU7ZEhWrSHi9p .error-icon{fill:#552222;}#mermaid-svg-k8jkU7ZEhWrSHi9p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-k8jkU7ZEhWrSHi9p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .marker.cross{stroke:#333333;}#mermaid-svg-k8jkU7ZEhWrSHi9p svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-k8jkU7ZEhWrSHi9p p{margin:0;}#mermaid-svg-k8jkU7ZEhWrSHi9p .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .cluster-label text{fill:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .cluster-label span{color:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .cluster-label span p{background-color:transparent;}#mermaid-svg-k8jkU7ZEhWrSHi9p .label text,#mermaid-svg-k8jkU7ZEhWrSHi9p span{fill:#333;color:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .node rect,#mermaid-svg-k8jkU7ZEhWrSHi9p .node circle,#mermaid-svg-k8jkU7ZEhWrSHi9p .node ellipse,#mermaid-svg-k8jkU7ZEhWrSHi9p .node polygon,#mermaid-svg-k8jkU7ZEhWrSHi9p .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .rough-node .label text,#mermaid-svg-k8jkU7ZEhWrSHi9p .node .label text,#mermaid-svg-k8jkU7ZEhWrSHi9p .image-shape .label,#mermaid-svg-k8jkU7ZEhWrSHi9p .icon-shape .label{text-anchor:middle;}#mermaid-svg-k8jkU7ZEhWrSHi9p .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .rough-node .label,#mermaid-svg-k8jkU7ZEhWrSHi9p .node .label,#mermaid-svg-k8jkU7ZEhWrSHi9p .image-shape .label,#mermaid-svg-k8jkU7ZEhWrSHi9p .icon-shape .label{text-align:center;}#mermaid-svg-k8jkU7ZEhWrSHi9p .node.clickable{cursor:pointer;}#mermaid-svg-k8jkU7ZEhWrSHi9p .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .arrowheadPath{fill:#333333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-k8jkU7ZEhWrSHi9p .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-k8jkU7ZEhWrSHi9p .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-k8jkU7ZEhWrSHi9p .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-k8jkU7ZEhWrSHi9p .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .cluster text{fill:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p .cluster span{color:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-k8jkU7ZEhWrSHi9p .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-k8jkU7ZEhWrSHi9p rect.text{fill:none;stroke-width:0;}#mermaid-svg-k8jkU7ZEhWrSHi9p .icon-shape,#mermaid-svg-k8jkU7ZEhWrSHi9p .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-k8jkU7ZEhWrSHi9p .icon-shape p,#mermaid-svg-k8jkU7ZEhWrSHi9p .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-k8jkU7ZEhWrSHi9p .icon-shape .label rect,#mermaid-svg-k8jkU7ZEhWrSHi9p .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-k8jkU7ZEhWrSHi9p .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-k8jkU7ZEhWrSHi9p .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-k8jkU7ZEhWrSHi9p :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 头部空间
GetHeadSpace()
可读数据
GetReadabeSpace()
尾部空间
GetTailSpace()
_reader_index
_writer_index
各个模块做的事情:
| 模块 | 作用 |
|---|---|
| 成员变量 | 用 vector<char> 保存数据,用两个下标记录读写位置 |
| 基础函数 | 获取读写位置、头部空间、尾部空间、可读空间 |
| 偏移函数 | 读完或者写完之后,移动对应下标 |
| 读取函数 | 从 Buffer 中读取数据,可以选择是否移动读下标 |
| 写入函数 | 向 Buffer 中写入数据,可以选择是否移动写下标 |
| 行处理函数 | 查找 \n,读取一整行数据 |
| 清理函数 | 把读写下标归零,表示 Buffer 当前没有可读数据 |
读数据的流程:
#mermaid-svg-pxhSvIxvkHuoYUzF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pxhSvIxvkHuoYUzF .error-icon{fill:#552222;}#mermaid-svg-pxhSvIxvkHuoYUzF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pxhSvIxvkHuoYUzF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pxhSvIxvkHuoYUzF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pxhSvIxvkHuoYUzF .marker.cross{stroke:#333333;}#mermaid-svg-pxhSvIxvkHuoYUzF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pxhSvIxvkHuoYUzF p{margin:0;}#mermaid-svg-pxhSvIxvkHuoYUzF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF .cluster-label text{fill:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF .cluster-label span{color:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF .cluster-label span p{background-color:transparent;}#mermaid-svg-pxhSvIxvkHuoYUzF .label text,#mermaid-svg-pxhSvIxvkHuoYUzF span{fill:#333;color:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF .node rect,#mermaid-svg-pxhSvIxvkHuoYUzF .node circle,#mermaid-svg-pxhSvIxvkHuoYUzF .node ellipse,#mermaid-svg-pxhSvIxvkHuoYUzF .node polygon,#mermaid-svg-pxhSvIxvkHuoYUzF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pxhSvIxvkHuoYUzF .rough-node .label text,#mermaid-svg-pxhSvIxvkHuoYUzF .node .label text,#mermaid-svg-pxhSvIxvkHuoYUzF .image-shape .label,#mermaid-svg-pxhSvIxvkHuoYUzF .icon-shape .label{text-anchor:middle;}#mermaid-svg-pxhSvIxvkHuoYUzF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pxhSvIxvkHuoYUzF .rough-node .label,#mermaid-svg-pxhSvIxvkHuoYUzF .node .label,#mermaid-svg-pxhSvIxvkHuoYUzF .image-shape .label,#mermaid-svg-pxhSvIxvkHuoYUzF .icon-shape .label{text-align:center;}#mermaid-svg-pxhSvIxvkHuoYUzF .node.clickable{cursor:pointer;}#mermaid-svg-pxhSvIxvkHuoYUzF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pxhSvIxvkHuoYUzF .arrowheadPath{fill:#333333;}#mermaid-svg-pxhSvIxvkHuoYUzF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pxhSvIxvkHuoYUzF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pxhSvIxvkHuoYUzF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pxhSvIxvkHuoYUzF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pxhSvIxvkHuoYUzF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pxhSvIxvkHuoYUzF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pxhSvIxvkHuoYUzF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pxhSvIxvkHuoYUzF .cluster text{fill:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF .cluster span{color:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pxhSvIxvkHuoYUzF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pxhSvIxvkHuoYUzF rect.text{fill:none;stroke-width:0;}#mermaid-svg-pxhSvIxvkHuoYUzF .icon-shape,#mermaid-svg-pxhSvIxvkHuoYUzF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pxhSvIxvkHuoYUzF .icon-shape p,#mermaid-svg-pxhSvIxvkHuoYUzF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pxhSvIxvkHuoYUzF .icon-shape .label rect,#mermaid-svg-pxhSvIxvkHuoYUzF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pxhSvIxvkHuoYUzF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pxhSvIxvkHuoYUzF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pxhSvIxvkHuoYUzF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 不需要
需要
是
否
调用 Read / ReadString
检查 len 是否小于等于可读空间
从 ReadPosition() 开始拷贝数据
是否需要 Pop?
只返回数据
不移动读下标
调用 MoveReadOffset(len)
读下标后移
reader == writer?
两个下标都归零
保留当前下标
写数据的流程:
#mermaid-svg-BOq3c2YdNiQirekh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BOq3c2YdNiQirekh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BOq3c2YdNiQirekh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BOq3c2YdNiQirekh .error-icon{fill:#552222;}#mermaid-svg-BOq3c2YdNiQirekh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BOq3c2YdNiQirekh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BOq3c2YdNiQirekh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BOq3c2YdNiQirekh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BOq3c2YdNiQirekh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BOq3c2YdNiQirekh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BOq3c2YdNiQirekh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BOq3c2YdNiQirekh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BOq3c2YdNiQirekh .marker.cross{stroke:#333333;}#mermaid-svg-BOq3c2YdNiQirekh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BOq3c2YdNiQirekh p{margin:0;}#mermaid-svg-BOq3c2YdNiQirekh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BOq3c2YdNiQirekh .cluster-label text{fill:#333;}#mermaid-svg-BOq3c2YdNiQirekh .cluster-label span{color:#333;}#mermaid-svg-BOq3c2YdNiQirekh .cluster-label span p{background-color:transparent;}#mermaid-svg-BOq3c2YdNiQirekh .label text,#mermaid-svg-BOq3c2YdNiQirekh span{fill:#333;color:#333;}#mermaid-svg-BOq3c2YdNiQirekh .node rect,#mermaid-svg-BOq3c2YdNiQirekh .node circle,#mermaid-svg-BOq3c2YdNiQirekh .node ellipse,#mermaid-svg-BOq3c2YdNiQirekh .node polygon,#mermaid-svg-BOq3c2YdNiQirekh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BOq3c2YdNiQirekh .rough-node .label text,#mermaid-svg-BOq3c2YdNiQirekh .node .label text,#mermaid-svg-BOq3c2YdNiQirekh .image-shape .label,#mermaid-svg-BOq3c2YdNiQirekh .icon-shape .label{text-anchor:middle;}#mermaid-svg-BOq3c2YdNiQirekh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BOq3c2YdNiQirekh .rough-node .label,#mermaid-svg-BOq3c2YdNiQirekh .node .label,#mermaid-svg-BOq3c2YdNiQirekh .image-shape .label,#mermaid-svg-BOq3c2YdNiQirekh .icon-shape .label{text-align:center;}#mermaid-svg-BOq3c2YdNiQirekh .node.clickable{cursor:pointer;}#mermaid-svg-BOq3c2YdNiQirekh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BOq3c2YdNiQirekh .arrowheadPath{fill:#333333;}#mermaid-svg-BOq3c2YdNiQirekh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BOq3c2YdNiQirekh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BOq3c2YdNiQirekh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BOq3c2YdNiQirekh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BOq3c2YdNiQirekh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BOq3c2YdNiQirekh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BOq3c2YdNiQirekh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BOq3c2YdNiQirekh .cluster text{fill:#333;}#mermaid-svg-BOq3c2YdNiQirekh .cluster span{color:#333;}#mermaid-svg-BOq3c2YdNiQirekh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BOq3c2YdNiQirekh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BOq3c2YdNiQirekh rect.text{fill:none;stroke-width:0;}#mermaid-svg-BOq3c2YdNiQirekh .icon-shape,#mermaid-svg-BOq3c2YdNiQirekh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BOq3c2YdNiQirekh .icon-shape p,#mermaid-svg-BOq3c2YdNiQirekh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BOq3c2YdNiQirekh .icon-shape .label rect,#mermaid-svg-BOq3c2YdNiQirekh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BOq3c2YdNiQirekh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BOq3c2YdNiQirekh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BOq3c2YdNiQirekh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 够
不够
够
不够
不需要
需要
调用 Write / WriteString
EnsureWriteSpace(len)
尾部空间够吗?
直接写入
头部+尾部空间够吗?
把可读数据移动到开头
resize 扩容
是否需要 Push?
只写入
不移动写下标
调用 MoveWriteoffset(len)
重点理解:
Read()和Write()只负责拷贝数据,本身不移动下标。- 带
Pop的读取函数,会在读取之后移动_reader_index。 - 带
Push的写入函数,会在写入之后移动_writer_index。 EnsureWriteSpace()是写入之前的准备工作,用来保证后面一定有足够的空间写。GetLine()是读取一行,但是不删除这一行;GetLineAndPop()是读取一行,并且把这一行从 Buffer 中移走。Clear()不是真的清空 vector,而是把读写下标归零,这样就表示没有可读数据了。
一句话总结:
Buffer模块的本质就是:用一块连续内存保存字节流,再用读写两个下标维护哪些数据已经读过、哪些数据可以读取、哪些空间可以继续写入。
到这里,本篇文章就结束了。
这一篇主要是 muduo 网络库项目中的一个小模块,后续会继续完善整个网络库的其他部分。
感谢各位对本篇文章的支持。谢谢各位点个三连吧!

