• 1.4.C++项目:仿muduo库实现并发服务器之buffer模块的设计


    项目完整版在:

    一、buffer模块: 缓冲区模块

    在这里插入图片描述
    Buffer模块是一个缓冲区模块,用于实现通信中用户态的接收缓冲区和发送缓冲区功能。

    二、提供的功能

    存储数据,取出数据

    三、实现思想

    1.实现换出去得有一块内存空间,采用vector ,vector底层是一个线性的内存空间!

    (一)要素

    1.默认空间大小
    2.当前的读取数据位置!
    3.当前的写入数据位置!

    (二)操作

    1. 写入位置
      当前写入位置指向哪里,从哪里开始写入
      如果后续剩余空间不够了!
    2. 考虑整体缓冲区空闲空间是否足够!(因为读位置也会向后偏移,前后有可能有空闲空间)
      足够:将数据移动到起始位置
      不够:扩容,从当前写位置开始扩容足够大小!
      数据一旦写入成功,当前写位置,向后偏移!
    3. 读取数据
      当前的读取位置指向哪里,就从哪里开始读取,前提是有数据可读
      可读数据大小:当前写入位置,减去当前读取位置!

    (三)框架设计

    class buffer {
        private:
            std::vector<char> _buffer;
            // 位置是一个相对偏移量,而不是绝对地址!
            uint64_t _read_idx; // 读位置
            uint64_t _write_idx; // 写位置
        public:
            1. 获取当前写的位置
            2. 确保可写空间足够
            3. 获取前沿空间大小
            4. 获取后沿空间大小
            5. 将写入据位置向后移动指定长度
            6. 获取当前读取位置的地址!
            7. 获取可读空间大小
            8. 将读位置向后移动指定长度!
            9. clear
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    四、实现代码

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    #define BUFFER_SIZE 1024
    class Buffer {
        private:
            std::vector<char> _buffer; // 使用vector进行内存空间管理
            uint64_t _read_idx; // 读偏移
            uint64_t _write_idx; // 写偏移
        public:
            Buffer():_read_idx(0),_write_idx(0),_buffer(BUFFER_SIZE) {}
            char* begin() {return &*_buffer.begin();}
            // 获取当前写入起始地址
            char *writePosition() { return begin() + _write_idx;}
            // 获取当前读取起始地址
            char *readPosition() { return begin() + _read_idx; }
            // 获取缓冲区末尾空间大小 —— 写偏移之后的空闲空间,总体大小减去写偏移
            uint64_t tailIdleSize() {return _buffer.size() - _write_idx; }
            // 获取缓冲区起始空间大小 —— 读偏移之前的空闲空间
            uint64_t handIdleSize() {return _read_idx ;}
            // 获取可读空间大小 = 写偏移 - 读偏移 
            uint64_t readAbleSize() {return _write_idx - _read_idx ;} 
            // 将读偏移向后移动
            void moveReadOffset(uint64_t len) { 
              // 向后移动大小必须小于可读数据大小
                  assert(len <= readAbleSize());
                  _read_idx += len; 
              }
            // 将写偏移向后移动
            void moveWriteOffset(uint64_t len) { 
                  assert(len <= tailIdleSize());
                  _write_idx += len;
            }
            void ensureWriteSpace(uint64_t len)  {
              // 确保可写空间足够 (整体空间够了就移动数据,否则就扩容!)  
                if (tailIdleSize() >= len) return;
                // 不够的话 ,判断加上起始位置够不够,够了将数据移动到起始位置
                if (len <= tailIdleSize() + handIdleSize()) {
                    uint64_t rsz = readAbleSize(); //帮当前数据大小先保存起来
                    std::copy(readPosition(),readPosition() + rsz,begin()); // 把可读数据拷贝到起始位置
                    _read_idx = 0; // 读归为0
                    _write_idx = rsz; // 可读数据大小是写的偏移量!
                }
                else { // 总体空间不够!需要扩容,不移动数据,直接给写偏移之后扩容足够空间即可!
                    _buffer.resize(_write_idx + len);
    
                }
            }
            // 写入数据
            void Write(const void *data,uint64_t len) {
            
                    ensureWriteSpace(len);
                    const char *d = (const char*) data;
                    std::copy(d,d + len,writePosition());
            }
            void WriteAndPush(void* data,uint64_t len) {
                    Write(data,len);
                    moveWriteOffset(len);
            }
             void WriteStringAndPush(const std::string &data) {
                writeString(data);
               
                moveWriteOffset(data.size());
               
            }
            void writeString(const std::string &data) {
                    return Write(data.c_str(),data.size());
            }
            void writeBuffer(Buffer &data) {
                    return Write(data.readPosition(),data.readAbleSize());
            }
            void writeBufferAndPush(Buffer &data) {
                    writeBuffer(data);
                    moveWriteOffset(data.readAbleSize());
                    
            }
            std::string readAsString (uint64_t len) {
                    assert(len <= readAbleSize());
                    std::string str;
                    str.resize(len);
                    Read(&str[0],len);
                    return str;
            }
            void Read(void *buf,uint64_t len) {
                    // 读取数据 1. 保证足够的空间 2.拷贝数据进去
                    // 要求获取的大小必须小于可读数据大小!
                    assert(len <= readAbleSize());
                    std::copy(readPosition(),readPosition() + len,(char*)buf);
            }
            void readAndPop(void *buf,uint64_t len) {
                    Read(buf,len);
                    moveReadOffset(len);
            }
            // 逐步调试!!!!!
            std::string ReadAsStringAndPop(uint64_t len) {
                assert(len <= readAbleSize());
                std::string str = readAsString(len);
                moveReadOffset(len);
                return str;
            }
            char* FindCRLF() {
                    char *res = (char*)memchr(readPosition(),'\n',readAbleSize());
                    return res;
            }
            // 通常获取一行数据,这种情况针对是:
            std::string getLine() {
                    char* pos = FindCRLF();
                    if (pos == NULL) {
                        return "";
                    }
                    // +1 为了把换行数据取出来!
                    return readAsString(pos - readPosition() + 1);
            }
            std::string getLineAndPop() {
                    std::string str = getLine();
                    moveReadOffset(str.size());
                    return str;
            }
            void Clear() { // 清空缓冲区!clear
                    // 只需要将偏移量归0即可!
                    _read_idx = 0;
                    _write_idx = 0;
            }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128

    五、进行测试

    #include "server.hpp"
    using namespace std;
    // 控制打印信息!!!
    #define INF 0
    #define DBG 1
    #define ERR 2
    #define LOG_LEVEL INF
        #define LOG(level,format,...) do{\
        if (level < LOG_LEVEL) break;\
        time_t t = time(NULL);\
        struct tm *ltm = localtime(&t);\
        char tmp[23] = {0};\
        strftime(tmp,31,"%H:%M:%S",ltm);\
        fprintf(stdout,"[%s,%s:%d] " format "\n",tmp,__FILE__,__LINE__,##__VA_ARGS__);\
    }while(0)
    
    #define INF_LOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
    #define DBG_LOG(format, ...) LOG(DBG, format, ##__VA_ARGS__)
    #define ERR_LOG(format, ...) LOG(ERR, format, ##__VA_ARGS__)
    
    int main() {
        Buffer buf;
        std::string str = "hello!";
        // buf.WriteStringAndPush(str);
        // Buffer buf1;
        // buf1.writeBufferAndPush(buf);
        // std::string tmp;
        // tmp = buf1.ReadAsStringAndPop(buf.readAbleSize());
        // cout << tmp << endl;
        // cout << buf.readAbleSize() << endl;
        // cout << buf1.readAbleSize() << endl;
        for (int i = 0; i < 300; i ++) {
            std::string str = "hello" + std::to_string(i) + '\n';
            buf.WriteStringAndPush(str);
        }
        while(buf.readAbleSize() > 0) {
            string line = buf.getLineAndPop();
            LOG("hello");  
        }
        // string tmp;
        // tmp = buf.ReadAsStringAndPop(buf.readAbleSize());
        // cout << tmp << endl;
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    中秋快乐!

  • 相关阅读:
    Linux 的 grep
    二十三种设计模式全面解析-适配器模式的妙用:异构数据库和不同版本API的完美兼容!
    实践历练的力量
    MAC终端美化
    听懂未来:AI语音识别技术的进步与实战
    aws-msk-托管kafka集群的简单使用(VPC内部访问:无验证和SASL认证)
    19 学生端注册与登录
    扩展Conda的宇宙:使用conda config --append channels命令
    嵌入式分享合集36
    MybatisPlus
  • 原文地址:https://blog.csdn.net/weixin_54447296/article/details/133429811