webserver--Buffer类实现内存缓冲区读写(全代码)

简介: webserver--Buffer类实现内存缓冲区读写(全代码)

  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());
    }
}
相关文章
|
4天前
|
存储 缓存 Java
Java中的缓冲流提升I/O性能,通过内存缓冲区减少对硬件访问
【6月更文挑战第22天】Java中的缓冲流提升I/O性能,通过内存缓冲区减少对硬件访问。`BufferedInputStream`和`BufferedOutputStream`用于字节流,缓存数据批量读写。`BufferedReader`和`BufferedWriter`处理字符流,支持按行操作。使用后务必关闭流。
15 3
|
23天前
|
消息中间件 存储 测试技术
【消息队列开发】 实现MemoryDataCenterTests类——测试管理内存数据
【消息队列开发】 实现MemoryDataCenterTests类——测试管理内存数据
|
1月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用合集之idea本地测试代码,要增大 Flink CDC 在本地 IDEA 测试环境中的内存大小如何解决
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
23天前
|
监控 Rust 安全
Rust代码在公司电脑监控软件中的内存安全监控
使用 Rust 语言开发的内存安全监控软件在企业中日益重要,尤其对于高安全稳定性的系统。文中展示了如何用 Rust 监控内存使用:通过获取向量长度和内存大小来防止泄漏和溢出。此外,代码示例还演示了利用 reqwest 库自动将监控数据提交至公司网站进行实时分析,以保证系统的稳定和安全。
88 2
|
23天前
|
消息中间件 存储 安全
【消息队列开发】 实现MemoryDataCenter类——管理内存数据
【消息队列开发】 实现MemoryDataCenter类——管理内存数据
|
2天前
|
存储 Java
JavaSE 面向对象程序设计初级 静态static 包package 常量final 代码块 代码实操理论内存原理详解
JavaSE 面向对象程序设计初级 静态static 包package 常量final 代码块 代码实操理论内存原理详解
6 0
|
29天前
|
移动开发 监控 Android开发
构建高效Android应用:从内存优化到电池寿命代码之美:从功能实现到艺术创作
【5月更文挑战第28天】 在移动开发领域,特别是针对Android系统,性能优化始终是关键议题之一。本文深入探讨了如何通过细致的内存管理和电池使用策略,提升Android应用的运行效率和用户体验。文章不仅涵盖了现代Android设备上常见的内存泄漏问题,还提出了有效的解决方案,包括代码级优化和使用工具进行诊断。同时,文中也详细阐述了如何通过减少不必要的后台服务、合理管理设备唤醒锁以及优化网络调用等手段延长应用的电池续航时间。这些方法和技术旨在帮助开发者构建更加健壮、高效的Android应用程序。
|
13天前
|
程序员 C++
c++primer plus 6 读书笔记 第十二章 类和动态内存分配
c++primer plus 6 读书笔记 第十二章 类和动态内存分配
|
28天前
|
存储 Java 编译器
Java方法的基本内存原理与代码实例
Java方法的基本内存原理与代码实例
22 0
|
1月前
|
存储 编译器 C++
【C++】内存管理和模板基础(new、delete、类及函数模板)
【C++】内存管理和模板基础(new、delete、类及函数模板)
34 1