C++ WebServer的细节理解

1. 文件描述符-非阻塞模式

fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0) | O_NONBLOCK);

代码解释:
上面这句代码,先查询文件描述符 fd 当前的标志,然后将 O_NONBLOCK 标志加入,并通过 F_SETFL 更新文件描述符,最终实现将该文件描述符切换为非阻塞模式。

O_NONBLOCK 设置在文件描述符上时,后续对该文件描述符的 I/O 操作(读写等)会变为非阻塞模式。

在非阻塞模式下,如果 I/O 操作不能立即完成(例如,因为没有数据可读 或 写缓冲区满),系统不会让调用进程阻塞等待,而是立即返回一个错误(通常为 EAGAIN 或 EWOULDBLOCK)。
这样,进程可以避免因等待 I/O 完成而被长时间阻塞,实现更高的响应性和并发性。

非阻塞模式—应用场景举例:

int accept(int sockfd, struct sockaddr* addr, socklen_t* len)

accept()函数,用于接受客户端的连接请求。默认情况下,accept() 是阻塞的。这意味着,如果没有待处理的连接请求(即没有客户端尝试连接到服务器),accept() 会一直阻塞,直到有新的连接请求到达或发生其他特定条件(如超时)为止。

当 accept() 处于阻塞状态时,它所在的线程是不能去做其他事情的。
若要改变这种行为,可以采用以下方法:

  1. 非阻塞模式:如前所述,可以使用 fcntl() 函数将套接字设置为非阻塞模式(使用 O_NONBLOCK 标志)。在这种模式下,accept() 调用将不会阻塞,而是立即返回。如果此时没有待处理的连接请求,accept() 将返回一个错误(通常为 EAGAINEWOULDBLOCK)。这样,线程可以在没有可用连接时执行其他任务,然后在适当的时候再次尝试 accept()

  2. 异步 I/O:如 Linux 中的 io_uring 或 Windows 中的 overlapped I/O,可以异步地执行 accept(),使得线程在发起 accept() 请求后可以继续执行其他任务,然后通过回调、事件通知等方式获知 accept() 的结果。

2. mmap() 和 munmap()

mmap() 和 munmap() 是用于内存映射操作的系统调用函数。
mmap() 允许将文件或其他对象直接映射到进程的虚拟地址空间中,从而实现高效的数据访问。

void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
  • void* addr

    • 指定映射开始的期望虚拟地址。如果设为 NULL,内核将自动选择一个合适的地址。
  • size_t length

    • 指定映射区域的长度。必须是页面大小的整数倍。
  • int prot

    • 控制映射区域的访问权限:
      • PROT_READ:允许读取。
      • PROT_WRITE:允许写入。
      • PROT_NONE:禁止访问。
  • int flags

    • 控制映射行为和映射内容的处理方式:
      • MAP_SHARED:创建一个可共享的映射,对映射区域的修改会影响到所有映射此区域的进程,并且可能会同步回文件。
      • MAP_PRIVATE:创建一个私有映射,对映射区域的修改仅影响当前进程,不会改变底层文件。
  • int fd

    • 用于指定要映射的文件。如果使用匿名映射,可以传入 -1 或者一个未打开的文件描述符。
  • off_t offset

    • 文件中的偏移量,映射从该位置开始。通常应是文件系统块大小的整数倍。

返回值:

  • 成功时返回映射区域的起始地址。
  • 出现错误时返回 MAP_FAILED(通常是一个负值,如 (void*) -1)。

int munmap(void* addr, size_t length);
  • void* addr
    • 指定要解除映射的内存区域的起始地址,该地址应是之前 mmap() 调用返回的地址。
  • size_t length
    • 指定解除映射的区域长度,应与对应的 mmap() 调用中的 length 参数一致。

返回值: 成功时返回 0。出现错误时返回 -1


mmap() 常用于以下场景:

  • 高效文件访问:将文件直接映射到内存,避免了常规的文件I/O操作,对于大数据文件或频繁访问的文件尤其高效。
  • 进程间通信(IPC):通过映射同一份共享内存,不同进程可以直接通过内存地址来交换数据,无需通过管道、套接字等传统IPC机制。

例如,映射一个已打开文件的部分内容到内存中:

#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cerrno>int main() {const char* filename = "/path/to/file";int fd = open(filename, O_RDONLY);if (fd == -1) {perror("open");return 1;}struct stat sb;if (fstat(fd, &sb) == -1) {perror("fstat");close(fd);return 1;}// 映射整个文件void* mapped_region = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (mapped_region == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 使用映射区域...// ...// 解除映射if (munmap(mapped_region, sb.st_size) == -1) {perror("munmap");close(fd);return 1;}close(fd);return 0;
}

在WebServer中,使用方法也类似;


int stat(const char *path, struct stat *buf);stat((srcDir_ + path_).data(), &mmFileStat_);

stat() 是一个标准C库函数,通常在 <sys/stat.h> 头文件中声明,用于获取文件或目录的状态信息。

  • const char *path: 一个指向包含文件路径的指针。可以是绝对路径,也可以是相对于当前工作目录的相对路径。
  • struct stat *buf: 一个指向 struct stat 结构体的指针,用于接收由 stat() 函数填充的关于指定路径对象的信息,例如:
    – 文件大小(st_size
    – 最近访问、修改和状态更改时间(st_atime, st_mtime, st_ctime
    – 权限位(st_mode

函数返回值:

  • 如果成功,返回0;否则,返回一个非零值(通常是错误代码),表示发生了某种错误(如权限不足、路径不存在等)。

3. struct iovec

struct iovec 是用于系统调用 readvwritev 的一个数据结构,这两个系统调用允许你从多个缓冲区读取数据或者向多个缓冲区写入数据。
使用 iovec 结构,可以指定多个缓冲区,每个缓冲区都有自己的地址和长度。这对于高效地处理I/O操作非常有用。

struct iovec 结构在 <sys/uio.h> 头文件中定义:

struct iovec {void  *iov_base;  /* 指向缓冲区的指针 */size_t iov_len;   /* 缓冲区的大小 */
};

在服务器中,声明 struct iovec iov_[2]; 时,实际上创建了一个包含两个 iovec 结构的数组。
这使得可以同时指定两个不同的缓冲区进行读写操作。例如,如果你想从文件中读取一些数据到两个不同的缓冲区,你可以这样做:

#include <iostream>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>int main() {const char* filename = "example.txt";int fd = open(filename, O_RDONLY);if (fd == -1) {std::cerr << "Failed to open file\n";return 1;}char buffer1[100], buffer2[100];struct iovec iov[2] = {{ .iov_base = buffer1, .iov_len = sizeof(buffer1) },{ .iov_base = buffer2, .iov_len = sizeof(buffer2) }};ssize_t bytesRead = readv(fd, iov, 2);if (bytesRead == -1) {std::cerr << "Error reading from file\n";close(fd);return 1;}close(fd);return 0;
}

其中,readv(fd, iov, 2); 函数用于从文件描述符 fd 指向的文件中,按照 iov 数组中指定的顺序和大小,一次性读取数据到由 iov 描述的多个缓冲区中。这里的 2 表示数组 iov 中有两个 iovec 结构体,即两个缓冲区。

  1. readv 函数: 与常规的 read 函数不同,readv 允许将数据读、写到多个缓冲区中,而不是单一的一个。有时也将readv和writev函数称为散布读(scatter read)和聚集写(gather write)。

  2. 使用 readv 可以在单个系统调用中完成对多个缓冲区的数据读取,可以提高效率,减少上下文切换和系统调用的开销。

  3. readv 函数的返回值是实际读取的字节数,它在任何错误发生时返回 -1。

4. 服务器如何发送响应

  • 在建立连接后,如果收到了某个fd有可读事件,
  • 服务器先调用readv读取数据(http请求)
  • 然后对原数据进行解析
  • 根据解析内容,服务器端进行可能的操作(如在数据库内进行增删改查)
  • 在缓冲区中生成响应行和响应头(包括文件的映射作响应体)
  • 设置fd为EPOLLOUT
  • 由EPOLLOUT触发writev(fd_, iov_, iovCnt_); 向socket上写入服务器处理客户请求的结果。

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

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

相关文章

【UE C++】打印输出的两种方式

目录 一、UE_LOG 二、调试屏幕信息 一、UE_LOG 定义&#xff1a; UE_LOG 是一个将格式化消息记录到日志文件中的宏。 用法&#xff1a; UE_LOG(LogTemp, Warning, TEXT("Hello World")); 第一个输入参数 LogTemp 是提供给 DEFINE_LOG_CATEGORY 宏的类别名称。你…

OpenAIGPT-4.5提前曝光?

OpenAI GPT-4.5的神秘面纱&#xff1a;科技界的震撼新篇章 在人工智能的世界里&#xff0c;每一次技术的飞跃都不仅仅是一次更新&#xff0c;而是对未来无限可能的探索。近日&#xff0c;科技巨头OpenAI似乎再次站在了这场革命的前沿&#xff0c;其潜在的新产品——GPT-4.5 Tur…

使用gdb调试遇到No symbol table is loaded. Use the “file“ command.怎么办?

问题排查 出现下面问题&#xff0c;通常是没有处于调式模式环境下&#xff0c;所以我们需要在gcc指令后加 【-g】。 因为&#xff0c;我么的gcc编辑器默认是动态链接&#xff0c;而且是realese发布版本。 想要解决也很简单 主要思路就是在gcc -g。 在makefile文件如下进行修改即…

MySQL面试题入门:四大范式、SQL生命周期、SQL六大语言、索引、最左匹配原则....

1、数据库四大范式&#xff1f; 第一范式&#xff1a;属性不可分割&#xff0c;即每个属性都是不可分割的原子项。(实体的属性即表中的列) 第二范式&#xff1a;满足第一范式&#xff1b;且不存在部分依赖&#xff0c;即非主属性必须完全依赖于主属性。(主属性即主键&#xf…

tar 和 zip 打包压缩命令

1. tar 文件的归档 tar [选项] 归档压缩后生成的文件 打包文件常用参数&#xff1a;-c # 创建文件-x # 提取解压还原文件-v # 显示详细执行过程-f # 指定备份文件-t # 列出压缩包中包括哪些文件&#xff0c;不解包&#xff0c;查看包中的内容-C # 指定解压位置 #对/o…

Kubernetes(K8S)特性有哪些?

Kubernetes简介 Kubernetes是一个开源的容器编排引擎&#xff0c;用于自动部署、扩展和管理容器化应用程序。它提供了一个平台来管理容器化应用程序的部署、扩展、自动化操作、服务发现和负载均衡等功能&#xff0c;让开发者能够更轻松地管理和运行容器化应用程序。 Kubernet…

Unity | 集成 Protobuf(proto 转 cs 插件及序列化与反序列化)

1. 添加 dll 1. 下载 protobuf 源码 根据需要下载 protobuf 指定版本的源码&#xff0c;这里以 v3.21.12&#xff08;protobuf-csharp-3.21.12.zip&#xff09;为例&#xff1a; 下载地址&#xff1a;「https://github.com/protocolbuffers/protobuf/releases」 2. 下载 Vis…

Java面试之JVM篇(共七篇---完结)

Java面试之虚拟机篇&#xff08;一&#xff09;&#xff1a;JVM概述与内存结构 在Java的面试中&#xff0c;虚拟机&#xff08;JVM&#xff09;是必考的知识点之一。作为Java程序运行的基础环境&#xff0c;JVM对Java的性能和稳定性有着至关重要的影响。本文将首先介绍JVM的基…

常见内网代理工具及其应用

常见内网代理工具 1. 正向代理&#xff1a;Squid原理示例 2. 反向代理&#xff1a;Nginx原理示例 3. SOCKS代理&#xff1a;Shadowsocks原理示例 零基础入门学习路线视频配套资料&国内外网安书籍、文档网络安全面试题 常见的内网代理工具包括多种类型&#xff0c;如正向代理…

自从用上电路仿真软件后,我才领悟到的4大奥秘

在电子工程领域&#xff0c;电路仿真软件已成为设计师们不可或缺的得力助手。自从我开始使用这款软件&#xff0c;它不仅极大提升了我的工作效率&#xff0c;还让我领悟到了许多前所未有的知识。今天&#xff0c;就让我来分享自从用上电路仿真软件后&#xff0c;我才知道的4件事…

【必须收藏】一文汇编山西省太原市及各地市区高新技术企业认定申报奖励优惠政策

一、山西省及各地市区高新技术企业申报奖励 &#xff08;高企、政策项目申报、专利商标版权DL&#xff01;zi询见个人简介 [疑难解答]&#xff09; &#xff08;一&#xff09;太原市高新技术企业申报奖励政策 建立高新技术企业培育库&#xff0c;对入库两年内通过高新技术企…

【分享】WinRAR软件如何压缩文件?

WinRAR是一款功能强大的压缩文件管理工具&#xff0c;支持多种压缩文件格式&#xff0c;那如何使用WinRAR来压缩文件呢&#xff1f;不清楚的小伙伴一起来看看吧&#xff01; 压缩方法&#xff1a; 首先&#xff0c;安装好WinRAR工具&#xff0c;然后选中需要压缩的文件或文件夹…

OSPF的学习笔记

1.OSPF &#xff08;1&#xff09;链路状态路由协议的路由信息并不是像距离矢量路由协议那样(邻居告诉的)&#xff0c;通过收集自身以及邻居发出的LSA(原材料)&#xff0c;并LSA放到指定仓库里面(LSDB)&#xff0c;通过SPF算法&#xff0c;以自己为根计算到达网络每个节点的最优…

Linux文件/目录高级管理三 头歌

1Linux文件/目录setuid和setgid 编程要求 在右侧编辑器中补充代码&#xff0c;具体编程要求如下&#xff1a; 使用助记语法为系统已存在文件oldFile1(默认权限为&#xff1a;rw_rw_r__)设置setuid权限; 使用助记语法为系统已存在目录oldDir1(默认权限为&#xff1a;rwxrwxrw…

php跨域和https访问http问题分析

1、https的web访问http地址的资源 问题&#xff1a;请求状态status(canceled) 解决办法&#xff1a;把资源地址改成https的 /*** HTTP地址改成HTTPS地址* param $url*/ function changeHttp2Https(&$url){if(stripos($url, http://) ! false){$url str_replace(http…

手机图片制作动态gif怎么做?不能错过的好用网站!

现在手机可是人人不离手的&#xff0c;而且手机上的很多软件功能已经逐渐取代了电脑。有时候我们想要把手机中的照片变成有动态效果的gif动图还不想下载软件的时候&#xff0c;就可以用Gif在线制作网站&#xff0c;不用下载软件&#xff0c;手机电脑都能在线操作。非常的方便小…

小孩近视用白炽灯好吗?分享多款央视推荐的护眼台灯

很多家长关心&#xff0c;小孩近视用白炽灯好吗&#xff1f;首先肯定是不太建议的&#xff0c;虽说白炽灯价格便宜&#xff0c;显色较好&#xff0c;不过光线会比较集中刺眼&#xff0c;而且由于是发热发光&#xff0c;也存在一定的安全隐患&#xff0c;更重要的是光衰现象会比…

道可云元宇宙每日资讯|广东:打造人工智能、新型储能等新增长点

道可云元宇宙每日简报&#xff08;2024年4月25日&#xff09;讯&#xff0c;今日元宇宙新鲜事有&#xff1a; 广东&#xff1a;打造人工智能、新型储能等新增长点 日前&#xff0c;广东省委常委会召开会议&#xff0c;会议指出&#xff0c;聚焦完善产业体系&#xff0c;统筹推…

Linux Docker下载镜像更改默认存储位置/usr/lib/docker

用于解决docker默认存储位置磁盘空间不足&#xff0c;切换存储位置 1、执行下面命令查看 现在docker的存储位置 docker info | grep "Docker Root Dir" 1.2、如果之前已经下载过镜像可以用mv命令把原来的镜像复制到新的地址 mv /var/lib/docker /data/docker 2、…

考研日常记录(upd 24.4.24)

由于实在太无聊了 &#xff0c; 所以记录以下考研备考日常 &#xff0c; 增加一点成就感 &#xff0c; 获得一点前进动力。 文章目录 2024.4.18 周四课程情况&#xff1a;时间规划&#xff1a; 2024.4.19 周五课程情况&#xff1a;时间规划&#xff1a; 2024.4.20 周六2024.4.2…