重写muduo之Buffer

news2025/1/20 5:56:23

1、 Buffer.h

Buffer封装

是一个缓冲区

prependable bytes+readable bytes+writable bytes=8字节长度(解决粘包问题)+读数据+写数据
根据下标进行读或者写

3个成员变量:数组,数据可读的下标,数据可写的下标

#pragma once

#include <vector>
#include <string>
#include <algorithm>

//网络库底层的缓冲区类型定义
class Buffer
{
public:
    static const size_t kCheapPrepend=8;//记录数据包的长度
    static const size_t kInitialSize=1024;//缓冲区的大小

    explicit Buffer(size_t initialSize=kInitialSize)
        :buffer_(kCheapPrepend+initialSize)
        ,readerIndex_(kCheapPrepend)
        ,writerIndex_(kCheapPrepend)
    {}

    size_t readableBytes() const//可读的缓冲区大小
    {
        return writerIndex_-readerIndex_;
    }

    size_t writableBytes() const//可写的缓冲区大小
    {
        return buffer_.size()-writerIndex_;
    }

    size_t prependableBytes() const//prependable Bytes区域大小
    {
        return readerIndex_;
    }

    //返回缓冲区中可读数据的起始地址
    const char* peek() const
    {
        return begin()+readerIndex_;
    }

    //注册回调  onMessage 有读写事件发生时,将buffer->string
    void retrieve(size_t len)
    {
        if(len<readableBytes())
        {
            readerIndex_+=len;//应用只读取了可读缓冲区数据的一部分,就是len,还剩下readerIndex_+=len~writerIndex_没读
        }
        else//len==readableBytes()
        {
            retrieveAll();
        }
    }

    void retrieveAll()
    {
        readerIndex_=writerIndex_=kCheapPrepend;
    }

    //把onMessage函数上报的Buffer数据,转成string类型的数据返回
    std::string retrieveAllAsString()
    {
        return retrieveAllAsString(readableBytes());//应用可读取数据的长度
    }

    std::string retrieveAllAsString(size_t len)
    {
        std::string result(peek(),len);//peek() 可读数据的起始地址
        retrieve(len);//上面一句把缓冲区中可读的数据,已经读取出来,这里肯定要对缓冲区进行复位操作
        return result;
    }

    //剩余的可写缓冲区buffer_.size()~writerIndex_    要写的数据的长度  len
    void ensureWriteableBytes(size_t len)
    {
        if(writableBytes()<len)
        {
            makeSpace(len);//扩容函数
        }
    }

    //把[data,data+len]内存上的数据,添加到writable缓冲区当中
    void append(const char* data,size_t len)
    {
        ensureWriteableBytes(len);//确保空间可用
        std::copy(data,data+len,beginWrite());
        writerIndex_+=len;
    }

    char* beginWrite()//可以写的地方的地址
    {
        return begin()+writerIndex_;
    }

    const char* beginWrite()const//常对象可调用
    {
        return begin()+writerIndex_;
    }

    //从fd上读取数据
    ssize_t readFd(int fd,int* saveErrno);

    //通过fd发送数据
    ssize_t writeFd(int fd,int* saveErrno);

private:
    char* begin()
    {
        //it.operator*()  取迭代器访问的第一个元素,再对这个元素取地址
        return &*buffer_.begin();//vector底层数组首元素的地址,也就是数组的起始地址
    }
    const char* begin() const
    {
        return &*buffer_.begin();
    }

    void makeSpace(size_t len)
    {
        /*
        kCheapPrepend  |  reader    |     writer     |
        kCheapPrepend  |           len               |
        */
        if(writableBytes()+prependableBytes()<len+kCheapPrepend)//writableBytes()+prependableBytes()=>可写缓存区长度+已读完数据已经空闲下来的缓冲区
        {
            buffer_.resize(writerIndex_+len);//扩容
        }
        else//将未读数据和可写缓冲区往前挪
        {
            size_t readalbe=readableBytes();//未读数据长度
            std::copy(begin()+readerIndex_,//将未读数据挪到前面
                    begin()+writerIndex_,
                    begin()+kCheapPrepend);
            readerIndex_=kCheapPrepend;//readerIndex_前移
            writerIndex_=readerIndex_+readalbe;//writerIndex_前移
        }
    }
    std::vector<char> buffer_;
    size_t readerIndex_;
    size_t writerIndex_;
};

2、Buffer.cc 

readv()可以根据读出的数据,自动填充多个缓冲区,这些缓冲区不需要连续
iovec:缓冲区的起始地址,缓冲区的长度

#include "Buffer.h"

#include <errno.h>
#include <sys/uio.h>
#include <unistd.h>

/**
 * 从fd上读取数据  Poller工作在LT模式
 * Buffer缓冲区是有大小的!  但是从fd上读数据的时候  却不知道tcp数据最终的大小
*/
ssize_t Buffer::readFd(int fd,int* saveErrno)
{
    char extrabuf[65536]={0};//栈上的内存空间  64k

    struct iovec vec[2];

    const size_t writable=writableBytes();//这是Buffer底层缓冲区剩余的可写空间大小
    vec[0].iov_base=begin()+writerIndex_;//缓冲区的起始地址
    vec[0].iov_len=writable;//缓冲区的长度

    //如果vec[0]缓冲区够填的话,就填充到vec[0],不够填,就填到vec[1],最后,如果我们看到vec[1]中有内容的话,就把其中的内容直接添加到缓冲区中
    //缓冲区刚刚好存入所有我们需要写入的内容,不浪费空间,空间利用率高
    vec[1].iov_base=extrabuf;
    vec[1].iov_len=sizeof extrabuf;

    const int iovcnt=(writable<sizeof extrabuf)?2:1;
    const ssize_t n=::readv(fd,vec,iovcnt);
    if(n<0)
    {
        *saveErrno=errno;
    }
    else if(n<=writable)//Buffer的可写缓冲区已经够存储读出来的数据了
    {
        writerIndex_+=n;
    }
    else//extrabuf里面也写入了数据
    {
        writerIndex_=buffer_.size();
        append(extrabuf,n-writable);//writerIndex_开始写n-writable大小的数据
    }
    
    return n;//读取的字节数
}

// 通过fd发送数据
ssize_t Buffer::writeFd(int fd, int *saveErrno)
{
    ssize_t n=::write(fd,peek(),readableBytes());
    if(n<0)//错误
    {
        *saveErrno=errno;
    }
    return n;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1667663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

打印图案(金字塔)头歌作业

题目: 任务描述 本关任务&#xff1a;编写一个程序&#xff0c;输出堆叠式的金字塔图案。 输入n个字符&#xff0c;按以下原则输出&#xff1a;【参考样例】 1)第1个字符为一层金字塔图案&#xff0c;第2个字符为两层金字塔图案&#xff0c;第3个字符为三层金字塔图案&#x…

C语言——文件缓冲区

一、用户缓冲区和系统缓冲区 缓冲区的概念确实可以分为多个层次&#xff0c;其中最常见的两个层次是用户缓冲区和系统缓冲区。 这里的用户缓冲区和系统缓冲区都包括输入输出缓冲区。 1、用户缓冲区&#xff08;User-space Buffer&#xff09; 用户缓冲区是指由用户程序&…

使用 Spring Boot 配合策略模式增强系统接口扩展能力

使用 Spring Boot 配合策略模式增强系统接口扩展能力 在软件开发中&#xff0c;系统的可扩展性是一个至关重要的方面。而策略模式是一种常见的设计模式&#xff0c;它可以帮助我们实现灵活的算法选择和系统功能扩展。结合 Spring Boot 框架&#xff0c;我们可以更加方便地利用策…

AVL 树的理解和简单实现

目录 1. AVL 树 1.1. AVL 树的概念 1.2. AVL 树的性质 2. AVL 树的框架如下 2. AVL树的 插入 2.1. 平衡因子的更新 2.2.1. 平衡因子更新的第一种情况 2.2.2. 平衡因子更新的第二种情况 2.2.3. 平衡因子更新的第三种情况 2.2.4. 平衡因子更新的代码框架如下 2.2. AV…

十一、Redis持久化-RDB、AOF

Redis提供了两种持久化数据的方式。一种是RDB快照&#xff0c;另一种是AOF日志。RDB快照是一次全量备份&#xff0c;AOF日志是连续的增量备份。RDB快照是以二进制的方式存放Redis中的数据&#xff0c;在存储上比较紧凑&#xff1b;AOF日志记录的是对内存数据修改的指令文本记录…

Run ‘conda init‘ before ‘conda activate‘

使用conda activate 虚拟环境名称的时候提示&#xff1a;Run conda init before conda activate 解决办法&#xff1a; 首先需要确保是管理员身份运行这个cmd窗口。 然后&#xff0c;现在执行一下&#xff1a;conda init 命令&#xff0c;最后再执行&#xff1a;conda activate…

React 第二十七章 Hook useCallback

useCallback 是 React 提供的一个 Hook 函数&#xff0c;用于优化性能。它的作用是返回一个记忆化的函数&#xff0c;当依赖发生变化时&#xff0c;才会重新创建并返回新的函数。 在 React 中&#xff0c;当一个组件重新渲染时&#xff0c;所有的函数都会被重新创建。这可能会…

Qt---事件

一、Qt中的事件 鼠标事件 鼠标进入事件enterEvent 鼠标离开事件leaveEvent 鼠标按下mousePressEvent ( QMouseEvent ev) 鼠标释放mouseReleaseEvent 鼠标移动mouseMoveEvent ev->x()&#xff1a;坐标 ev->y()&#xff1a;y坐标 ev->bu…

day11-IO流

IO流 1 IO流的概述和分类 1.1学习IO流的目的&#xff1f; 1&#xff0c;将数据写到文件中&#xff0c;实现数据永久化存储 2&#xff0c;读取文件中已经存在的数据 1.2 IO流概述 其中&#xff1a;I表示intput&#xff0c;是数据从硬盘进内存的过程&#xff0c;称之为读。…

远程调用feign的使用

在orderservice子工程中 <!--feign的远程--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>启动类加上这个注解 EnableFeignClients //自动装配…

Python+PySpark数据计算

1、map算子 对RDD内的元素进行逐个处理&#xff0c;并返回一个新的RDD&#xff0c;可以使用lambda以及链式编程&#xff0c;简化代码。 注意&#xff1a;再python中的lambda只能有行&#xff0c;如果有多行&#xff0c;要写成外部函数&#xff1b;&#xff08;T&#xff09;-&…

考研操作系统-1.计算机系统概述

王道考研操作系统-1.计算机系统概述 操作系统 是指控制和管理整个计算机系统的硬件和软件资源&#xff0c;合理地组织调度计算机的工作和资源的分配&#xff1b;提供给用户和软件方便的接口和环境&#xff1b;是计算机系统中最基本的系统软件。 应包括&#xff1a; 1&#xf…

阿里云 物联网平台 MQTT连接、数据传输

阿里云 物联网平台 MQTT连接、数据传输 1、设备连接阿里云 2、多设备之前的通信、数据流转 3、设备数据来源的读取。 基于C# winform 开发上位机&#xff0c;读取设备、仪器、MES或者电子元器件的数据&#xff0c;MQTT传输至阿里云平台&#xff0c;可视化界面构建界面&#…

Kafka应用Demo:指派分区订阅消息消费

环境准备 Kafka环境搭建和生产者样例代码与《Kafka应用Demo&#xff1a;按主题订阅消费消息》相同。 消费者代码样例 public class KafkaConsumerService {private static final Logger LOGGER LoggerFactory.getLogger(KafkaConsumerService.class);private static final S…

练习队列的相关操作:循环队列

1. 思路解析 循环队列就是在只有有限的空间时使用队列实现循环存储数据&#xff0c;有双向链表和数组两种选择&#xff0c;这里我们使用数组实现循环队列&#xff08;因为链表我不会 >-<&#xff09; 2. 相关函数及其实现 2.1 判空与判满 判空&#xff1a;直接返回头尾…

NX/UG二次开发—3D几何—多边形内部最大圆

多边形内部最大圆&#xff0c;为什么不能说最大内切圆&#xff1f;如果正方形或正凸多边形&#xff0c;最大内部圆是与边相切的&#xff0c;但对于不规则多边形&#xff0c;很多情况是正好经过一些凹点。 本次介绍在NX中计算封闭边界内部最大圆&#xff1a; 1、首先按顺序排序…

ASP.NET一种基于C2C模式的网上购物系统的设计与实现

摘 要 网络购物已经慢慢地从一个新鲜的事物逐渐变成日常生活的一部分&#xff0c;以其特殊的优势而逐渐深入人心。本课题是设计开发一种基于C2C模式的网上购物系统。让各用户使用浏览器进行商品浏览。注册用户可以轻松的展示自己的网络商店&#xff0c;能对自己的用户信息进行…

华为机试打卡 HJ2 计算某字符出现次数

要机试了&#xff0c;华孝子求捞&#xff0c;功德 描述 写出一个程序&#xff0c;接受一个由字母、数字和空格组成的字符串&#xff0c;和一个字符&#xff0c;然后输出输入字符串中该字符的出现次数。&#xff08;不区分大小写字母&#xff09; 数据范围&#xff1a; 1≤&a…

SM935,SM942,SM150和利时备件

SM935,SM942,SM150和利时备件。组态软件&#xff0c;可组态控制图、机柜布置图、电源分配图等&#xff0c;可编辑、编译、SM935,SM942,SM150和利时备件。工程师站组态的基本步骤&#xff1a;SM935,SM942,SM150和利时备件。 1. 根据生产现场的控制方案画出控制系统原理图 2. 根据…

自动秒收录网址导航分类目录模板

自动秒收录网址导航是一个以html5css3进行开发的免费版网址自动收录模板源码。 模板特点&#xff1a;全站响应式H5网站制作技术&#xff0c;一个网站适应不同终端&#xff0c;模板支持网址导航一键采集入库&#xff0c;免规则文章资讯智能批量采集内置伪原创&#xff0c;本地化…