C++类Buffer的实现,用于处理内存缓冲区的读写操作。Buffer类封装了一个固定大小的字符数组,提供了一系列方法来管理这个缓冲区中的数据。
一般的Buffer缓冲区实现是个什么过程呢?
初始化:首先,需要初始化一个 Buffer 对象,用于存储待处理的数据。可以指定缓冲区的大小以及其他相关参数。
写入数据:一旦 Buffer 对象被初始化,可以通过不同的方法向其写入数据。这些方法通常包括直接写入字符串、从文件读取数据写入、从另一个缓冲区复制数据等。
读取数据:一旦数据被写入缓冲区,可以使用相应的读取方法从缓冲区中读取数据。这些方法可能包括读取指定长度的数据、读取直到特定分隔符的数据、以及将数据转换为不同的格式等。
处理数据:读取到数据后,可以对其进行各种处理,例如解析 HTTP 请求、执行业务逻辑、或者转发数据给其他模块。
清空缓冲区:在数据被处理完毕后,可以选择清空缓冲区,以释放内存空间,并准备接收新的数据。
异常处理:在读写过程中可能会出现各种异常情况,例如缓冲区溢出、读取到不完整的数据等,需要相应的异常处理机制来处理这些情况,以确保系统的稳定性和可靠性。
几个重要的函数 :
构造函数 Buffer::Buffer(int initBuffSize):
初始化缓冲区大小为initBuffSize。
设置读位置readPos_和写位置writePos_为0,表示缓冲区开始时是空的。
Buffer::EnsureWriteable(size_t len):
确保缓冲区有足够的空间写入len个字节的数据,如果没有,则通过调整缓冲区大小或重新排列数据来提供空间。
Buffer::ReadFd(int fd, int* saveErrno):
从文件描述符fd读取数据到缓冲区,如果读取成功,更新写位置。
Buffer::WriteFd(int fd, int* saveErrno):
将缓冲区中的数据写入到文件描述符fd。
Buffer::BeginPtr_() 和 Buffer::BeginPtr_() const:
返回指向缓冲区开始的指针。
Buffer::MakeSpace_(size_t len):
如果需要的空间大于当前可写空间和可前置空间的总和,重新分配缓冲区大小;否则,将可读数据向前移动,为新数据腾出空间
完整代码:(太不容易了,点个赞呗,可以关注一下公众号和视频号^_^)
#include "buffer.h" // 构造函数,初始化缓冲区大小、读位置和写位置 Buffer::Buffer(int initBuffSize) : buffer_(initBuffSize), readPos_(0), writePos_(0) {} // 返回可读的字节数 size_t Buffer::ReadableBytes() const { return writePos_ - readPos_; } // 返回可写的字节数 size_t Buffer::WritableBytes() const { return buffer_.size() - writePos_; } // 返回可前置的字节数 size_t Buffer::PrependableBytes() const { return readPos_; } // 返回指向当前读位置的指针 const char* Buffer::Peek() const { return BeginPtr_() + readPos_; } // 移动读位置len个字节 void Buffer::Retrieve(size_t len) { assert(len <= ReadableBytes()); readPos_ += len; } // 移动读位置,直到达到end指向的位置 void Buffer::RetrieveUntil(const char* end) { assert(Peek() <= end); Retrieve(end - Peek()); } // 清空整个缓冲区,并将读位置和写位置重置为0 void Buffer::RetrieveAll() { bzero(&buffer_[0], buffer_.size()); readPos_ = 0; writePos_ = 0; } // 将当前可读的数据转换为字符串,并清空缓冲区 std::string Buffer::RetrieveAllToStr() { std::string str(Peek(), ReadableBytes()); RetrieveAll(); return str; } // 返回指向当前写位置的只读指针 const char* Buffer::BeginWriteConst() const { return BeginPtr_() + writePos_; } // 返回指向当前写位置的可写指针 char* Buffer::BeginWrite() { return BeginPtr_() + writePos_; } // 移动写位置len个字节,表示写入了len个字节的数据 void Buffer::HasWritten(size_t len) { writePos_ += len; } // 将字符串str追加到缓冲区末尾 void Buffer::Append(const std::string& str) { Append(str.data(), str.length()); } // 将数据data的len个字节追加到缓冲区末尾 void Buffer::Append(const void* data, size_t len) { assert(data); Append(static_cast<const char*>(data), len); } // 将字符串str的len个字节追加到缓冲区末尾 void Buffer::Append(const char* str, size_t len) { assert(str); EnsureWriteable(len); std::copy(str, str + len, BeginWrite()); HasWritten(len); } // 将另一个Buffer对象buff中的数据追加到当前缓冲区 void Buffer::Append(const Buffer& buff) { Append(buff.Peek(), buff.ReadableBytes()); } // 确保缓冲区有足够的空间写入len个字节的数据 void Buffer::EnsureWriteable(size_t len) { if(WritableBytes() < len) { MakeSpace_(len); } assert(WritableBytes() >= len); } // 从文件描述符fd读取数据到缓冲区 ssize_t Buffer::ReadFd(int fd, int* saveErrno) { char buff[65535]; struct iovec iov[2]; const size_t writable = WritableBytes(); iov[0].iov_base = BeginPtr_() + writePos_; iov[0].iov_len = writable; iov[1].iov_base = buff; iov[1].iov_len = sizeof(buff); const ssize_t len = readv(fd, iov, 2); if(len < 0) { *saveErrno = errno; } else if(static_cast<size_t>(len) <= writable) { writePos_ += len; } else { writePos_ = buffer_.size(); Append(buff, len - writable); } return len; } // 将缓冲区中的数据写入到文件描述符fd ssize_t Buffer::WriteFd(int fd, int* saveErrno) { size_t readSize = ReadableBytes(); ssize_t len = write(fd, Peek(), readSize); if(len < 0) { *saveErrno = errno; return len; } readPos_ += len; return len; } // 返回指向缓冲区开始的指针 char* Buffer::BeginPtr_() { return &*buffer_.begin(); } // 返回指向缓冲区开始的只读指针 const char* Buffer::BeginPtr_() const { return &*buffer_.begin(); } // 如果需要的空间大于当前可写空间和可前置空间的总和,重新分配缓冲区大小; // 否则,将可读数据向前移动,为新数据腾出空间 void Buffer::MakeSpace_(size_t len) { if(WritableBytes() + PrependableBytes() < len) { buffer_.resize(writePos_ + len + 1); } else { size_t readable = ReadableBytes(); std::copy(BeginPtr_() + readPos_, BeginPtr_() + writePos_, BeginPtr_()); readPos_ = 0; writePos_ = readPos_ + readable; assert(readable == ReadableBytes()); } }