重写muduo之Buffer

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->stringvoid 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_    要写的数据的长度  lenvoid 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};//栈上的内存空间  64kstruct 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.hqwc.cn/news/691311.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费思维13招之六:功能型思维

免费思维13招之六&#xff1a;功能型思维 这节来学习一下免费思维的另一大思维——功能型思维。 这个思维通俗易懂。功能型思维是指将其他产品的功能在我们的产品上进行体现&#xff0c;让客户获得免费的使用。 也就是说&#xff0c;客户买了你的产品&#xff0c;却可以免费得…

常见算法策略

前言 算法策略是指在解决问题或完成任务时所采用的方法、技巧或步骤的总称。 在设计算法时&#xff0c;通常会考虑多种策略&#xff0c;并选择最适合特定问题的策略来实现算法的设计和优化。 算法策略比较 动态规划 动态规划介绍入口

基于LLM的自行车道CAD

LLM&#xff08;大型语言模型&#xff09;是强大的工具。对于许多人来说&#xff0c;用语言表达愿望通常比浏览复杂的 GUI 更简单。 1、系统简介和环境搭建 urb-x.ch&#xff0c;这是一家专门从事自行车道建设的公司。轨道采用模块化构建块进行独特设计&#xff0c;可以通过多…

一个优秀 Maven 项目,各 Model 间最佳继承设计方案

1.单一职责原则 (Single Responsibility Principle): 每个模块应该专注于执行一个清晰且明确定义的功能&#xff0c;遵循单一职责原则&#xff0c;以降低模块的复杂性。 2.高内聚性 (High Cohesion): 模块内的组件和类应该紧密相关&#xff0c;共同实现模块的目标。高内聚性…

网安面经之SSRF漏洞

一、ssrf漏洞 1、ssrf原理&#xff1f;危害&#xff1f;修复&#xff08;防御&#xff09;&#xff1f; 原理&#xff1a;SSRF就是服务器端请求伪造漏洞、它是一种由攻击者构造&#xff0c;由服务端发起请求的一个网络攻击&#xff0c;一般用来在外网探测或攻击内网服务&…

【PHP【实战版】系统性学习】——登录注册页面的教程,让编写PHP注册变成一个简单的事情

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

iOS 安装cocoapds

注意 CocoaPods安装是基于ruby环境的&#xff0c;所以要安装CocoaPods先要安装Ruby环境&#xff0c;国内不能直接安装&#xff0c;只能通过VPN或淘宝的Ruby镜像来访问。 安装过程 gem sources --remove https://rubygems.org/ ** (注意是两个“-”&#xff0c;否则会移除失败) …

Python的while循环

目录 while循环的结构 示例 关键字 break continue while循环的结构 while condition&#xff08;循环条件&#xff09;: # 循环的内容 循环内容的执行与结束需要通过循环条件控制。 在执行循环之前需要设立一个循环条件的初始值&#xff0c;以便while循环体判断循环条件。…

社交媒体数据恢复:密聊猫

一、概述 密聊猫是一款提供多种优质体验的手机社交聊天软件。通过这款软件&#xff0c;用户可以享受到多种不同的乐趣体验&#xff0c;如真人在线匹配、真实的交友体验等。同时&#xff0c;密聊猫也提供了数据恢复功能&#xff0c;帮助用户找回丢失的数据。 二、数据恢复步骤…

【计算机毕业设计】基于SSM++jsp的公司员工信息管理系统【源码+lw+部署文档+讲解】

目录 1 绪论 1.1 研究背景 1.2 目的和意义 1.3 论文结构安排 2 相关技术 2.1 SSM框架介绍 2.2 B/S结构介绍 2.3 Mysql数据库介绍 3 系统分析 3.1 系统可行性分析 3.1.1 技术可行性分析 3.1.2 经济可行性分析 3.1.3 运行可行性分析 3.2 系统性能分析 3.2.1 易用性指标 3.2.2 可…

中霖教育:考消防工程师有专业限制吗?

想要参加消防工程师考试&#xff0c;有专业限制吗? 其实是没有的&#xff0c;无论是否为消防工程专业都可以报名参加考试&#xff0c;只不过非专业人员的工作年限和从事相关工作的年限会要求多一年。 限制条件&#xff1a; 报考消防工程师主要有学历、工作年限、消防安全技…

神经网络复习--神经网络算法模型及BP算法

文章目录 神经网络模型的构成BP神经网络 神经网络模型的构成 三种表示方式&#xff1a; 神经网络的三要素&#xff1a; 具有突触或连接&#xff0c;用权重表示神经元的连接强度具有时空整合功能的输入信号累加器激励函数用于限制神经网络的输出 感知神经网络 BP神经网络 …