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

160 Linux C++ 通讯架构实战14,epoll 反应堆模型

到这里,我们需要整理一下之前学习的epoll模型,并根据之前的epoll模型,提出弊端,进而整理epoll反应堆模型,进一步深刻理解,这是因为epoll实在是太重要了。

复习之前的epoll的整体流程以及思路。

参考之前写的epoll的代码

第一步,socket,创建套接字。

int listenfd = Socket(AF_INET, SOCK_STREAM,0);

第二步,setsockopt 设定端口复用

int opt = 1;
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

第三步, bind函数,将socket和地址结构绑定

Bind(listenfd, (struct sockaddr *)&servaddr,sizeof(servaddr));

第四步,Listen 设置可以同时监听的最大的数量为1024

Listen(listenfd, 1024);

第五步,Epoll_create 创建一个红黑树结点,建议的节点>0

int epfd = Epoll_create(OPEN_MAX);

第六步,Epoll_ctl 先将listenfd添加到 epfd这个红黑树上,EPOLL_CTL_ADD表示是添加节点.EPOLLIN表示监听读事件

    struct epoll_event event;
    bzero(&event, sizeof(event));
    event.events = EPOLLIN; 
    event.data.fd = listenfd;
    //epoll_ct 函数的目的是给这颗红黑树上添加节点,删除节点,修改节点
    Epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd, &event);

第七步,epoll_wait,这时候就需要弄一个循环监听了, 使用 epoll_wait函数等待连接

while (1) {
        //epoll_wait返回值nready为满足监听的总个数。realevents是传出参数,传出满足监听条件的所有的结构体
        nready = epoll_wait(epfd, realevents, OPEN_MAX, -1);

}

第7.1步:

epoll_wait返回后,如果realevents 中的是listenfd,说明有客户端第一次连接过来,需要使用accpet去接受这个链接,生成clientfd ,

int clientfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen);

然后将这个clientfd添加到红黑树上。

                Epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &clientevent);

第7.2步:

epoll_wait返回后,如果realevents 中的是clientfd,那么说明客户端有发真正的数据过来,需要使用read 函数去读取这些数据,完成我们对于数据的处理,然后再使用write发给客户端

realreadnum = Read(socketfd, buf, MAXLINE);

//将读到的数据做处理,我们这里只是小写转大写。
for (int j = 0; j < realreadnum; ++j) {
        buf[j] = toupper(buf[j]);
}
Write(socketfd, buf, realreadnum);

这里会有问题,这是因为在网络环境下,环境是很复杂的,例如:客户端的 滑动窗口 已经满了

fix 方案:epoll 反应堆模型

接上述条件,因此在这里我们需要判断客户端是否能写,如果能写,也就是说:我们需要将 clientfd 的 “写事件” 加入到红黑树上。写完后,将 clientfd 的“写事件” 从红黑树上摘下。

还有一个问题,当我们接受的这些数据还没有处理的时候,我们不希望从 clientfd 再 “读取数据”,因此还需要将 clientfd 的“读事件” 从 红黑树上摘下,等待 给客户端 写数据完成后,再将 读取数据事件  添加回 红黑树上。

整个整理如下:

如果realevents中是clientfd--------> read 数据

-------->将clientfd 从红黑树上摘下(将clientfd 的 读事件通过epoll_del  从 红黑树上摘下),

-------->将clientfd 的写事件 通过epoll_ctl上添加到红黑树上

-------->当epoll_wait的返回时,如果返回中有 写事件 ,再使用write /send 发送数据给客户端

-------->当发送数据完成后,则将clientfd 的写事件从红黑树上摘下

-------->将clientfd 的读事件再次添加到红黑树上,从而形成循环

epoll反应堆模型的再次说明:

在epoll反应堆模型之前,我们需要使用到 epoll_event 中的 data 中的 fd来决定具体是那个连接

struct epoll_event
{uint32_t events;	/* Epoll events */epoll_data_t data;	/* User data variable */
} __EPOLL_PACKED;

typedef union epoll_data
{void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;

在epoll反应堆的时候,我们需要使用到 epoll_event 中的 data 中的 ptr

因为ptr是一个万能指针,可以指向任何东西,因此一般使用的时候,会有一个struct,将相关的信息都放在这个struct中,且这个ptr就指向这个ptr,这样就能保存所有的信息,且会将 epoll_wait成立需要调用的方法,通过回调函数的形式添加到这个struct中,

实际上是多了个参数的使用::   ET + NONBLOCK  轮询 + void *ptr

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/epoll.h>#include "wrap.h"
#define MAXLINE 8192
#define SERV_PORT 8000
#define OPEN_MAX 5000int main() {int ret = 0;//第一步,socket,创建套接字。On  success,  a  file  descriptor  for  the new socket is returnedint listenfd = Socket(AF_INET, SOCK_STREAM,0);//第二步,setsockopt 设定端口复用,代码是固定的,当opt是1的时候,说明可以复用端口。 On success, zero is returned for the standard options.  On error, -1 is returned, and errno is set appropriately.int opt = 1;Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//第三步, bind函数,将socket和地址结构绑定//int Bind(int fd, const struct sockaddr *sa, socklen_t salen)struct sockaddr_in servaddr;bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);Bind(listenfd, (struct sockaddr *)&servaddr,sizeof(servaddr));//第四步,设置可以同时监听的最大的数量为1024,如果改成5000会不会错呢?Listen(listenfd, 1024);//Listen(listenfd, OPEN_MAX);//第五步,创建一个红黑树结点,我们建议这个红黑树的节点为5000int epfd = Epoll_create(OPEN_MAX);//第六步,先将listenfd添加到 epfd这个红黑树上,EPOLL_CTL_ADD表示是添加节点.EPOLLIN表示监听读事件struct epoll_event event;bzero(&event, sizeof(event));event.events = EPOLLIN; event.data.fd = listenfd;//epoll_ct 函数的目的是给这颗红黑树上添加节点,删除节点,修改节点Epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd, &event);//第七步,这时候就需要弄一个循环监听了, 使用 epoll_wait函数等待连接struct epoll_event realevents[OPEN_MAX];int nready = 0;while (1) {//epoll_wait返回值nready为满足监听的总个数。realevents是传出参数,传出满足监听条件的所有的结构体nready = epoll_wait(epfd, realevents, OPEN_MAX, -1);if (nready == -1) {perr_exit("epoll_wait error");}for (int i = 0; i < nready;++i) {if (!(realevents[i].events & EPOLLIN)) {//如果不是"读"事件, 继续循环continue;}int socketfd = realevents[i].data.fd;if (socketfd == listenfd) {//如果是listenfd 的读事件,说明有新的链接过来了,这时候要调用accpetstruct sockaddr_in cliaddr;int cliaddrlen = sizeof(cliaddr);bzero(&cliaddr, cliaddrlen);printf("aaa\n");int clientfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen);char str[INET_ADDRSTRLEN] = {0};//#define INET_ADDRSTRLEN 16printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));//然后将connfd,添加到红黑树上struct epoll_event clientevent;bzero(&clientevent, sizeof(clientevent));clientevent.events = EPOLLIN;clientevent.data.fd = clientfd;Epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &clientevent);}else {//如果不是listenfd,那么就是connectfd了,说明这时候客户端有东西写过来,我们要从客户端读取数据char buf[MAXLINE] = {0};int realreadnum;REREADPOINT:realreadnum = Read(socketfd, buf, MAXLINE);if (realreadnum == 0) {//在网络环境下,read函数返回0,说明是对端关闭了,也就是说,客户端关闭了//那么就应该关闭当前的connect端,并将该监听从 红黑树上 移除printf("read done\n");Epoll_ctl(epfd, EPOLL_CTL_DEL, socketfd, NULL);Close(socketfd);}else if (realreadnum == -1) {if (errno == EINTR) {//说明是被信号打断的,一般要重新readprintf("信号打断\n");goto REREADPOINT;}else if (errno == EAGAIN || errno == EWOULDBLOCK){printf(" WOULDBLOCK \n");//说明在打开文件的时候是使用的O_NONBLOCK方式打开的,但是没有读取到数据//当前代码是不会走到这里的,因为前面代码select的最后一个参数用的NULL,是阻塞的//一般在这里 也要重新读,但是这里有个问题,如果一直都读取不到,会不会死循环?goto REREADPOINT;}else if (errno == ECONNRESET) {//ECONNRESET 说明连接被重置了,因此要将该cfd关闭,并重新移除监听队列printf("read done\n");Epoll_ctl(epfd, EPOLL_CTL_DEL, socketfd, NULL);Close(socketfd);}else {//这就是真正的有问题了,注意这里不要exit程序,应该只是让打印log//不退出程序是因为,这时候还有其他的链接连上的perror("read num <0");}}else if (realreadnum > 0) {//真正的读取到了客户端发送过来的数据for (int j = 0; j < realreadnum; ++j) {buf[j] = toupper(buf[j]);}Write(socketfd, buf, realreadnum);Write(STDOUT_FILENO, buf, realreadnum);}}}}Close(listenfd);Close(epfd);return ret;
}

相关文章:

160 Linux C++ 通讯架构实战14,epoll 反应堆模型

到这里&#xff0c;我们需要整理一下之前学习的epoll模型&#xff0c;并根据之前的epoll模型&#xff0c;提出弊端&#xff0c;进而整理epoll反应堆模型&#xff0c;进一步深刻理解&#xff0c;这是因为epoll实在是太重要了。 复习之前的epoll的整体流程以及思路。 参考之前写…...

根据mysql的执行顺序来写select

过滤顺序指的是mysql的逻辑执行顺序&#xff0c;个人觉得我们可以按照执行顺序来写select查询语句。 目录 一、执行顺序二、小tips三、案例第一轮查询&#xff1a;统计每个num的出现次数第二轮查询&#xff1a;计算**最多次数**第三轮查询&#xff1a;找到所有出现次数为最多次…...

spring 和spring boot的区别

Spring是一个开源的Java开发框架&#xff0c;旨在简化Java应用程序的开发。它提供了一个综合的编程和配置模型&#xff0c;用于构建各种类型的应用程序&#xff0c;从简单的命令行工具到复杂的企业级Web应用程序。 Spring Boot是Spring框架的一个扩展&#xff0c;旨在简化Spri…...

Day84:服务攻防-端口协议桌面应用QQWPS等RCEhydra口令猜解未授权检测

目录 端口协议-口令爆破&未授权 弱口令爆破 FTP&#xff1a;文件传输协议 RDP&#xff1a;Windows远程桌面协议 SSH&#xff1a;Linux安全外壳协议 未授权案例(rsync) 桌面应用-QQ&WPS&Clash QQ RCE 漏洞复现 WPS RCE 漏洞复现 Clas* RCE 漏洞复现 知识点…...

视频分块上传Vue3+SpringBoot3+Minio

文章目录 一、简化演示分块上传、合并分块断点续传秒传 二、更详细的逻辑和细节问题可能存在的隐患 三、代码示例前端代码后端代码 一、简化演示 分块上传、合并分块 前端将完整的视频文件分割成多份文件块&#xff0c;依次上传到后端&#xff0c;后端将其保存到文件系统。前…...

深入浅出 -- 系统架构之单体到分布式架构的演变

一、传统模式的技术改革 在很多年以前&#xff0c;其实没有严格意义上的前后端工程师之分&#xff0c;每个后端就是前端&#xff0c;同理&#xff0c;前端也可以是后端&#xff0c;即Ajax、jQuery技术未盛行前的年代。 起初&#xff0c;大部分前端界面很简单&#xff0c;显示的…...

每日一题 第七十期 洛谷 [蓝桥杯 2020 省 AB2] 回文日期

[蓝桥杯 2020 省 AB2] 回文日期 题目描述 2020 年春节期间&#xff0c;有一个特殊的日期引起了大家的注意&#xff1a;2020 年 2 月 2 日。因为如果将这个日期按 yyyymmdd 的格式写成一个 8 8 8 位数是 20200202&#xff0c;恰好是一个回文数。我们称这样的日期是回文日期。…...

蓝桥杯第十四届C++A组(未完)

【规律题】平方差 题目描述 给定 L, R&#xff0c;问 L ≤ x ≤ R 中有多少个数 x 满足存在整数 y,z 使得 。 输入格式 输入一行包含两个整数 L, R&#xff0c;用一个空格分隔。 输出格式 输出一行包含一个整数满足题目给定条件的 x 的数量。 样例输入 1 5 样例输出 …...

职场口才提升之道

职场口才提升之道 在职场中&#xff0c;口才的重要性不言而喻。无论是与同事沟通协作&#xff0c;还是向上级汇报工作&#xff0c;亦或是与客户洽谈业务&#xff0c;都需要具备良好的口才能力。一个出色的职场人&#xff0c;除了拥有扎实的专业技能外&#xff0c;还应具备出色…...

【算法练习】28:选择排序学习笔记

一、选择排序的算法思想 弄懂选择排序算法&#xff0c;先得知道两个概念&#xff1a;未排序序列&#xff0c;已排序序列。 原理&#xff1a;以升序为例&#xff0c;选择排序算法的思想是&#xff0c;先将整个序列当做未排序的序列&#xff0c;以序列的第一个元素开始。然后从左…...

【关于窗口移动求和的两种计算方法】

窗口移动计算方法 例子方法1方法2运行结果: 例子 在很多算法中都会涉及到窗口滑动&#xff0c;比如基于新息序列更新的自适应卡尔曼滤波器算法中便会使用到。 已知一个数列&#xff1a;OCV [1;2;3;4;5;6;7;8;9;10;11;12;13;14;15]&#xff0c;定义窗口长度为5&#xff0c;每次…...

Win10文件夹共享(有密码的安全共享)(SMB协议共享)

前言 局域网内&#xff08;无安全问题&#xff0c;比如自己家里wifi&#xff09;无密码访问&#xff0c;参考之前的操作视频 【电脑文件全平台共享、播放器推荐】手机、电视、平板播放硬盘中的音、视频资源 下面讲解公共网络如办公室网络、咖啡厅网络等等环境下带密码的安全…...

Client sent an HTTP request to an HTTPS server

背景 最近踩坑了 我发现域名&#xff1a;8000可以访问我的服务 但是域名&#xff1a;443却不行&#xff0c;这很反常 结果发现是nginx配置的问题&#xff0c;需要把http改成https&#xff01; 原因 如果你的后端服务&#xff08;运行在8000端口上&#xff09;已经配置了SS…...

Springboot传参要求

Web.java(这里定义了一个实体类交Web) public class Web{ private int Page; public int getPage() {return Page;}public void setPage(int page) {Page page;} } 1、通过编译器自带的getter、Setter传参 。只是要注意参数的名字是固定的&#xff0c;不能灵活改变。 传参的…...

数字乡村创新实践探索:科技赋能农业现代化与乡村治理体系现代化同步推进

随着信息技术的飞速发展&#xff0c;数字乡村作为乡村振兴的重要战略方向&#xff0c;正日益成为推动农业现代化和乡村治理体系现代化的关键力量。科技赋能下的数字乡村&#xff0c;不仅提高了农业生产的效率和品质&#xff0c;也为乡村治理带来了新的机遇和挑战。本文旨在探讨…...

C语言——找单身狗1

题目描述&#xff1a; 在一个整形数组中&#xff0c;只有一个数字出现一次&#xff0c;其他数组都是成对出现的&#xff0c;找出那个只出现一次的数字。 例如&#xff1a; 数组中&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;4&#xff0c;3…...

Day82:服务攻防-开发组件安全Solr搜索Shiro身份Log4j日志本地CVE环境复现

目录 J2EE-组件Solr-本地demo&CVE 命令执行&#xff08;CVE-2019-17558&#xff09; 远程命令执行漏洞(CVE-2019-0193) Apache Solr 文件读取&SSRF (CVE-2021-27905) J2EE-组件Shiro-本地demo&CVE CVE_2016_4437 Shiro-550Shiro-721(RCE) CVE-2020-11989(身…...

网络协议——VRRP(虚拟路由冗余协议)原理与配置

1. VRRP概述 单网关出现故障后下联业务中断&#xff0c;配置两个及以上的网关时由于IP地址冲突&#xff0c;导致通讯时断时续甚至通信中断。VRRP组播类的网络层协议 2. 协议版本 VRRP v2: 支持认证,仅适用于IPv4网络 VRRP v3: 不支持认证&#xff0c; 适用于IPv4和IPv6两种网…...

Elasticsearch:我们如何演化处理二进制文档格式

作者&#xff1a;来自 Elastic Sean Story 从二进制文件中提取内容是一个常见的用例。一些 PDF 文件可能非常庞大 — 考虑到几 GB 甚至更多。Elastic 在处理此类文档方面已经取得了长足的进步&#xff0c;今天&#xff0c;我们很高兴地介绍我们的新工具 —— 数据提取服务&…...

第八讲 Sort Aggregate 算法

我们现在将讨论如何使用迄今为止讨论过的 DBMS 组件来执行查询。 1 查询计划【Query Plan】 我们首先来看当一个查询【Query】被解析【Parsed】后会发生什么&#xff1f; 当 SQL 查询被提供给数据库执行引擎&#xff0c;它将通过语法解析器进行检查&#xff0c;然后它会被转换…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...