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());
    }
}
相关文章
|
2月前
|
缓存 Java
Java内存管理秘籍:掌握强软弱幻四大引用,让代码效率翻倍!
【8月更文挑战第29天】在Java中,引用是连接对象与内存的桥梁,主要分为强引用、软引用、弱引用和幻象引用。强引用确保对象生命周期由引用控制,适用于普通对象;软引用在内存不足时可被回收,适合用于内存敏感的缓存;弱引用在无强引用时即可被回收,适用于弱关联如监听器列表;幻象引用需与引用队列配合使用,用于跟踪对象回收状态,适用于执行清理工作。合理使用不同类型的引用车可以提升程序性能和资源管理效率。
37 4
|
2月前
|
存储 程序员 Python
Python类的定义_类和对象的关系_对象的内存模型
通过类的定义来创建对象,我们可以应用面向对象编程(OOP)的原则,例如封装、继承和多态,这些原则帮助程序员构建可复用的代码和模块化的系统。Python语言支持这样的OOP特性,使其成为强大而灵活的编程语言,适用于各种软件开发项目。
18 1
|
2月前
|
存储 缓存 JSON
一行代码,我优化掉了1G内存占用
这里一行代码,指的是:String.intern()的调用,为了调用这一行代码,也写了几十行额外的代码。
|
2月前
|
前端开发 JavaScript Java
揭开 JavaScript 垃圾回收的秘密——一场与内存泄漏的生死较量,让你的代码从此焕然一新!
【8月更文挑战第23天】本文通过多个实例深入探讨了JavaScript中的垃圾回收机制及其对应用性能的影响。首先介绍了基本的内存管理方式,随后分析了变量不再使用时的回收过程。接着,通过事件监听器未被移除及全局变量管理不当等场景展示了常见的内存泄漏问题。最后,文章介绍了使用`WeakRef`和`FinalizationRegistry`等现代API来有效避免内存泄漏的方法。理解并运用这些技术能显著提升Web应用的稳定性和效率。
77 0
|
2月前
|
编译器 C++
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
|
2月前
|
easyexcel Java 关系型数据库
阿里巴巴-EasyExcel 基于Java的简单、省内存的读写Excel
该文章主要介绍了在Java应用中如何使用EasyExcel技术完成对Excel文件的导入和导出操作,包括环境搭建、基本概念、快速入门、进阶操作和综合应用等内容,并提供了相关代码示例和注意事项。
 阿里巴巴-EasyExcel 基于Java的简单、省内存的读写Excel
|
2月前
|
缓存 程序员
封装一个给 .NET Framework 用的内存缓存帮助类
封装一个给 .NET Framework 用的内存缓存帮助类
|
2月前
|
C++ 容器
curl使用小记(三)——获取远端数据到内存缓冲区
curl使用小记(三)——获取远端数据到内存缓冲区
43 0
|
3月前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
47 1
|
3月前
|
Java Perl
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列