当前位置: 首页 > news >正文

WebServer:buffer

这个应该是最先写的模块,因为缓冲区似乎是独立出来的。

buffer.h

sys/uio.h

这个头文件是Linux系统提供的用于IO操作的头文件,sys表明它是一个系统提供的头文件(类Unix系统提供的系统调用库似乎都是以sys开始的),uio表明它是一个Linux中的IO库(这个u我怀疑是Unix的意思)。
在该文件中,使用了其中的数据结构:

struct iovec { // 意思是io vectorvoid  *iov_base;  // 指向缓冲区的指针size_t iov_len;   // 缓冲区的长度
};

和关于该数据结构的两个函数:

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

使用iovec的好处在于:这两个函数能将一个文件描述符中的数据同时读/写到多个缓冲区中

ssizze_t和size_t的使用

在Buffer中,有很多在平时编写简短代码中不太常见的内容,如:size_tssize_t,这都是为了保证程序的可移植性,使用size_t作为函数返回值是为了和vector的size()匹配,而ssize_t则是因为和系统API进行了交互

ssize_t往往被声明为signed int

函数编写建议

因为上面这些小知识点,我们就能够得到一个结论:

  1. ssize_t:用于需要表示负值的场景,通常与系统API交互时,特别是在处理可能失败的操作和错误码时。
  2. size_t:用于处理不可能是负数的情况,如数组大小、容器容量和索引。

如果在编写程序的时候能够注意这些小问题,就能够提高我们编写的程序的可移植性。

关于调用系统调用

这个问题是源于Buffer的读写函数中:

ssize_t ReadFD(int fd, int* Errno);
ssize_t WriteFD(int fd, int* Errno);

[!问题描述]
系统调用不是会自动对一个全局变量errno进行设置吗?为什么这里还需要传入一个由我们维护的int* Errno

这是因为errno是一个全局变量,WebServer是一个多线程程序,在多线程中,直接使用errno很容易就会产生数据竞争的问题,而在单线程中,我们直接使用errno是没问题的

atomic的使用

C++参考手册其中有对atomic的详细描述,包括了C++20的,WebServer使用的标准好像是C++14,并没有用到20。

atomic的操作其实不算多:

#include <atomic>
std::atomic<int> example(100); // 定义一个int类型的atomic变量,并且将其值初始化为100
exampe = store(50); // 将值原子地变更为50
int value = example.load() // 读取值

以上是比较基础的用法,还有exchange()compare_exchange_weak()compare_exchange_strongis_lock_free()我这没说,我看了下感觉我用不上。

断言的使用

#include <cassert>
assert(condition);

当传入的condition为false的时候,断言就会被触发,它会调用abort()函数,终止程序的运行

assert的行为是可以被控制的,若是不想更改代码,同时又不希望assert被使用,可以定义一个宏:#define NDEBUG

在宏NDEBUG被声明的时候,assert不会被启用,即使它在2代码中被使用,也不会有任何行为。

这里我就发现很有意思的一点:

#define NDEBUG#include <assert.h>

这种情况下,NDEBUG才是有效的;若是define的声明在头文件导入之后,这个宏就不会起作用了,这是因为在头文件定义的时候就定义了这一点,我看了下asseert.h中的内容,发现了如下两行:

If NDEBUG is defined, do nothing.
If not, and EXPRESSION is zero, print an error message and abort.

其中就提到了NDEBUG的用法。

这个现象的解释就是在include之后它会检查之前是否有define过该宏。

vector中的clear()

void Buffer::RetrieveAll() {// bzero(&buffer_[0], buffer_.size());/*原版使用的是上面的注释部分但是这部分GPT说已经不建议使用了因为不符合C语言的编写标准*/memset(&buffer_[0], 0, buffer_.size());readPos_ = 0;writePos_ = 0;
}

迭代器的更深入理解

C++参考手册中说到:迭代器就是更为广义上的指针。所以它的使用和指针其实差不多,但是为什么我会写这个呢?

char* Buffer::BeginPtr_() {return &*buffer_.begin();
}

主要是这段代码在我一开始看的时候感觉有点莫名其妙,有点不是很理解为什么要这么写。但现在就能较好的说明它了:

[!解释]
对于begin()都很清楚返回值是一个迭代器,而迭代器是一个抽象的指针,它重载了指针的所有操作(解引用和取地址),并且效果和操作指针是一样的,但是迭代器毕竟不是指针。

arr.begin()就是获得arr的首部迭代器,而对其进行解引用就是获得arr的首部值,即:arr[0],再对其解引用就得到了头部的地址

string.data()

这个函数我一直都没怎么用过,因为我觉得这部分直接使用C语言的写法会更好一点,data()获得的是string的首部元素的地址,具体如下:

void Buffer::Append(const std::string& str) {Append(str.data(), str.size());
}

其实这段代码如果是我要写的话我应该会直接写&str[0],但是从代码的编写规范来说,我的写法是不那么“现代化C++”的,所以还是使用data()更好点。

static_cast

static_cast本身不会丢弃原对象的const和volatile属性

const int num = 10;
int temp = static_cast<int>(num);
temp = 12;

这里涉及到两个知识点:

  • static_cast 只是类型转换:
    • static_cast 进行的是类型转换,并不改变原始数据的 const 限制。它只是将 num 的值传递到 temp 中,temp 在这个过程中并不继承 const 限制。
  • const 限制在原始对象中有效:
    • const 限制仅对原始对象有效。在上面的例子中,num 是 const,所以你不能修改 num。但 temp 是一个新的 int 变量,它不受 num 的 const 限制影响。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 某省公共资源交易电子平台爬虫逆向
  • Spring Mybatis PageHelper分页插件 总结
  • 【JVM原理】运行时数据区(内存结构)
  • Open3D 利用点云的曲率密度提取特征点【2024最新版】
  • Linux1-ls,cd,pwd
  • Qt 模型视图(二):模型类QAbstractItemModel
  • 【自动驾驶】决策规划算法(一)决策规划仿真平台搭建 | Matlab + Prescan + Carsim 联合仿真基本操作
  • 信息安全工程师(8)网络新安全目标与功能
  • Python 如何调用讯飞星火大模型API
  • 【前端】ES6:Promise对象和Generator函数
  • 深度学习自编码器 - 自编码器的应用篇
  • 木舟0基础学习Java的第二十九天(Spring,Spring的属性注入(xml,注解))
  • 编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MinGW版)
  • leetcode第十四题:最长公共前缀
  • CTC loss 博客转载
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • CSS盒模型深入
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • FineReport中如何实现自动滚屏效果
  • javascript数组去重/查找/插入/删除
  • Java知识点总结(JavaIO-打印流)
  • socket.io+express实现聊天室的思考(三)
  • SpringBoot几种定时任务的实现方式
  • sublime配置文件
  • Vue.js 移动端适配之 vw 解决方案
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • Vue官网教程学习过程中值得记录的一些事情
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 程序员最讨厌的9句话,你可有补充?
  • 对超线程几个不同角度的解释
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 悄悄地说一个bug
  • 我的面试准备过程--容器(更新中)
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 一起参Ember.js讨论、问答社区。
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • (C++17) optional的使用
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (编译到47%失败)to be deleted
  • (多级缓存)多级缓存
  • (二)丶RabbitMQ的六大核心
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (回溯) LeetCode 46. 全排列
  • (排序详解之 堆排序)
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)WLAN定义和基本架构转
  • .NET gRPC 和RESTful简单对比
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 反射 Reflect
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件