基于多反应堆的高并发服务器【C/C++/Reactor】(中)在EventLoop中处理被激活的文件描述符的事件

文件描述符处理与回调函数

一、主要概念

  1. 反应堆模型:一种处理系统事件或网络事件的模型,当文件描述符被激活时,可以检测到
  2. 文件描述符:在操作系统中,用于标识打开的文件、套接字等的一种数据类型 
  3. 处理激活的文件描述符的函数:当文件描述符被激活时,需要有一个函数来处理这些事件
  4. dispatch函数:用于分发或处理不同类型事件的函数
  5. channel结构体:存储与文件描述符相关的事件处理动作的结构体
  6. 回调函数:在初始化channel对象时指定的读回调和写回调,用于处理不同类型的事件
  7. select函数:用于检测多个文件描述符的状态,看是否有数据可读可写
  8. fd_set集合:用于存储文件描述符的集合,通过宏函数FD_ISSET判断文件描述符是否被触发

二、处理流程

  1. 当反应堆模型启动,检测到被激活的文件描述符
  2. 调用dispatch函数,得到文件描述符fd
  3. 根据fdchannelMap中取出对应的channel,判断是读事件还是写事件
  4. 调用对应的回调函数,处理事件
  5. select函数中,通过fd_set集合判断是否有数据可读可写,调用eventActivate函数处理事件
  6. epoll函数中,通过epoll_wait进行检测,遍历返回的events数组,调用eventActivate函数处理事件
  7. poll函数中,通过poll进行检测,遍历返回的事件列表,调用eventActivate函数处理事件

三、注意事项

  • 在调用回调函数时,需要传入注册时指定的参数
  • 在使用回调函数时,需要注意处理函数的参数和返回值

四、概括

  • 本文主要介绍了在EventLoop中处理被激活的文件描述符的事件和回调机制
  • 反应堆模型启动时,可以检测到被激活的文件描述符,并使用dispatch函数获取文件描述符(EventLoop初始化和启动)
  • 根据文件描述符ChannelMap中取出对应的channel,判断是读事件还是写事件,并调用相应的回调函数处理

核心观点:

  1. 反应堆模型启动后,可以检测到被激活的文件描述符
  2. 使用dispatch函数获取文件描述符,并根据文件描述符从ChannelMap中取出对应的channel
  3. 根据channel判断是读事件还是写事件,并调用相应的回调函数处理
  4. select函数中,通过fd_set集合判断是否有数据可读可写,调用eventActivate函数处理事件
  5. epoll函数中,通过epoll_wait进行检测,遍历返回的events数组,调用eventActivate函数处理事件
  6. poll函数中,通过poll进行检测,遍历返回的事件列表,调用eventActivate函数处理事件

>>回顾ChannelMap 模块的实现Channel 模块的实现

  • Channel.h
// 定义函数指针
typedef int(*handleFunc)(void* arg);// 定义文件描述符的读写事件
enum FDEvent {TimeOut = 0x01;ReadEvent = 0x02;WriteEvent = 0x04;
};struct Channel {// 文件描述符int fd;// 事件int events;// 回调函数handleFunc readCallback;// 读回调handleFunc writeCallback;// 写回调// 回调函数的参数void* arg;
};

 >>在EventLoop中处理被激活的文件描述符的事件

  • EpollLoop.h 
// 处理被激活的文件描述符fd
int eventActivate(struct EventLoop* evLoop,int fd,int event);
  •  EpollLoop.c  
// 处理被激活的文件描述符fd
int eventActivate(struct EventLoop* evLoop,int fd,int event) {if(fd < 0 || evLoop == NULL) {+return -1;}// 取出channelstruct Channel* channel = evLoop->channelMap->list[fd];assert(channel->fd == fd);if(event & ReadEvent && channel->readCallback) {channel->readCallback(channel->arg);}if(event & WriteEvent && channel->writeCallback) {channel->writeCallback(channel->arg);}return 0;
}

>>回顾Dispatcher模块,Dispatcher模块的实现思路和定义 ,补充代码

  • SelectDispatcher.c  
static int selectDispatch(struct EventLoop* evLoop,int timeout) {struct SelectData* data = (struct SelectData*)evLoop->dispatcherData;struct timeval val;val.tv_sec = timeout;val.tv_usec = 0;fd_set rdtmp = data->readSet;fd_set wrtmp = data->writeSet;int count = select(Max,&rdtmp,&wrtmp,NULL,&val);if(count == -1) {perror("select");exit(0);}for(int i=0;i<Max;++i) { if(FD_ISSET(i,&rdtmp)) {// 已续写...eventActivate(evLoop,i,ReadEvent);}if(FD_ISSET(i,&wrtmp)) {// 已续写...eventActivate(evLoop,i,WriteEvent);}}return 0;
}
  • PollDispatcher.c  
static int pollDispatch(struct EventLoop* evLoop,int timeout) {struct PollData* data = (struct PollData*)evLoop->dispatcherData;int count = poll(data->fds,data->maxfd + 1,timeout * 1000);if(count == -1) {perror("poll");exit(0);}for(int i=0;i<=data->maxfd;++i) {if(data->fds[i].fd == -1) {continue;}if(data->fds[i].revents & POLLIN) {// 已续写...eventActivate(evLoop,data->fds[i].fd,ReadEvent);}if(data->fds[i].revents & POLLOUT) {// 已续写...eventActivate(evLoop,data->fds[i].fd,WriteEvent);}}return 0;
}
  • EpollDispatcher.c  
static int epollDispatch(struct EventLoop* evLoop,int timeout) {struct EpollData* data = (struct EpollData*)evLoop->dispatcherData;int count = epoll_wait(data->epfd,data->events,Max,timeout * 1000);for(int i=0;i<count;++i) {int events = data->events[i].events;int fd = data->events[i].data.fd;if(events & EPOLLERR || events & EPOLLHUP) {// 对方断开了连接,删除 fd// epollRemove(&evLoop->channels[fd],evLoop);continue;}if(events & EPOLLIN) {// 已续写...eventActivate(evLoop,fd,ReadEvent);}if(events & EPOLLOUT) {// 已续写...eventActivate(evLoop,fd,WriteEvent);}}return 0;
}

五、回顾select函数、poll函数、epoll_wait函数(CodeGeex生成)

  • select函数

Linux 中的 select 函数主要用于等待多个文件描述符(fd)就绪,从而可以一次性处理多个文件描述符。select 函数会检查指定的文件描述符是否就绪,如果其中任何一个是就绪的,则 select 函数返回。select 函数的原型为:

#include <sys/select.h>
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout);

其中,nfds 表示要检查的文件描述符数量,readfds、writefds 和 exceptfds 分别表示要检查的读、写和异常文件描述符集合,timeout 表示等待的时间限制。

例如,下面代码等待两个文件描述符(fd)就绪,最多等待 5 秒钟:

int fd1 = open("file1", O_RDONLY);
int fd2 = open("file2", O_RDONLY);fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd1, &readfds);
FD_SET(fd2, &readfds);struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;int ret = select(2, &readfds, NULL, NULL, &timeout);if (ret > 0) {if (FD_ISSET(fd1, &readfds)) {// fd1 is ready to read}if (FD_ISSET(fd2, &readfds)) {// fd2 is ready to read}
}
  • poll函数

Linux 中的 poll 函数与 select 函数类似,用于等待多个文件描述符就绪,但是 poll 函数返回的是一个事件列表,不是像 select 函数那样返回就绪的文件描述符数量poll 函数的原型为:

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

其中,fds 是一个 pollfd 结构数组,每个结构中包含一个文件描述符和一个事件掩码,timeout 表示等待的时间限制。

例如,下面代码使用 poll 函数等待两个文件描述符(FD)就绪,最多等待 5 秒钟:

int fd1 = open("file1", O_RDONLY);
int fd2 = open("file2", O_RDONLY);struct pollfd fds[2];
fds[0].fd = fd1;
fds[0].events = POLLIN;
fds[1].fd = fd2;
fds[1].events = POLLIN;int timeout = 5000; // 5 秒int ret = poll(fds, 2, timeout);if (ret > 0) {if (fds[0].revents & POLLIN) {// fd1 is ready to read}if (fds[1].revents & POLLIN) {// fd2 is ready to read}
}

如果 poll 函数返回 0,则表示超时,如果返回值大于 0,则表示有文件描述符就绪。与 select 函数不同的是,poll 函数返回的是一个事件列表,而不是具体的文件描述符。

  • epoll函数

Linux 中的 epoll 函数是 Linux 2.6.8 引入的一个新的 I/O 模型,它提供了高效的 I/O 事件通知机制,能够处理大量文件描述符,并且具有低延迟和高吞吐量的优点。

epoll 函数的原型为:

#include <sys/epoll.h>
int epoll_create(int size);
int epoll_ctl(int epoll_fd, int op, int fd, int event);
int epoll_wait(int epoll_fd, struct epoll_event *events, int maxevents, int timeout);

其中,epoll_create 函数用于创建一个 epoll 实例,size 参数指定要创建的 epoll 实例可以容纳的最大文件描述符数量。epoll_ctl 函数用于控制 epoll 实例,op 参数指定要进行的操作(例如,添加修改删除文件描述符),fd 参数指定要操作的文件描述符,event 参数指定要设置的事件掩码。epoll_wait 函数用于等待 epoll 实例中的文件描述符就绪,events 参数指向一个 epoll_event 结构数组,用于存储就绪的文件描述符和事件信息,maxevents 参数指定最多等待的文件描述符数量,timeout 参数指定等待的时间限制。

例如,下面代码使用 epoll 函数等待两个文件描述符(fd)就绪,最多等待 5 秒钟:

int fd1 = open("file1", O_RDONLY);
int fd2 = open("file2", O_RDONLY);int epoll_fd = epoll_create(10);struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd1;int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd1, &event);event.data.fd = fd2;
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd2, &event);struct epoll_event events[2];
int timeout = 5000; // 5 秒int num = epoll_wait(epoll_fd, events, 2, timeout);if (num > 0) {if (events[0].data.fd == fd1 && events[0].events & EPOLLIN) {// fd1 is ready to read}if (events[1].data.fd == fd2 && events[1].events & EPOLLIN) {// fd2 is ready to read}
}

如果 epoll 函数返回 0,则表示超时,如果返回值大于 0,则表示有文件描述符就绪。与 select poll 函数不同的是,epoll 函数能够处理大量的文件描述符,并且具有低延迟和高吞吐量的优点

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

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

相关文章

太阳能防外破智能地钉_灯光警示_定位-深圳鼎信

智能地钉是一种利用无线传感和无线通信技术来保护地下管道线路&#xff0c;防止地面施工或其它因素导致管道外破的装置。组成结构包括智能分析模块、陀螺仪传感器、无线模块、备用电池、太阳能板、金属防护外壳、北斗定位以及声光报警器等。 智能地钉镶嵌在地面上具有防水、耐腐…

算法——队列+宽搜(BFS)

队列这种数据结构大都服务于一个算法——宽搜&#xff08;BFS&#xff09;。宽搜还可以运用到二叉树、图、迷宫最短路径问题、拓扑排序等等 N叉数的层序遍历 N叉树的层序遍历 题目解析 给定一个 N 叉树&#xff0c;返回其节点值的_层序遍历_。&#xff08;即从左到右&#…

【python】—— 列表和元组详解

Python是一种强大的编程语言&#xff0c;它提供了许多内置的数据结构&#xff0c;用于存储和处理数据。其中&#xff0c;列表和元组是两种常用的数据类型。这篇文章将介绍这两种数据结构的定义、用途、用法以及它们的异同点。 目录 &#xff08;一&#xff09;理解列表和元组 …

面试题理解深层次的数组名

目录 引言 一&#xff1a;一维数组 举例如下 1.铺垫知识 数组名是数组首元素的地址&#xff0c;但是有两个特殊情况 &#xff08;1&#xff09;sizeof(数组名) &#xff08;2&#xff09;&数组名 2.分析讲解上述代码结果 2.字符数组 举例一如下 1.知识铺垫 …

软性演员-评论家算法 SAC

软性演员-评论家算法 SAC 软性演员-评论家算法 SAC优势原理软性选择模型结构目标函数重参数化熵正则化代码实现 软性演员-评论家算法 SAC 优势原理 DDPG 的问题在于&#xff0c;训练不稳定、收敛差、依赖超参数、不适应复杂环境。 软性演员-评论家算法 SAC&#xff0c;更稳定…

23款奔驰GLC260L升级香氛负离子 车载香薰

奔驰原厂香氛系统激活原车自带系统&#xff0c;将香气加藏储物盒中&#xff0c;通过系统调节与出风口相结合&#xff0c;再将香味传达至整个车厢&#xff0c;达到净化车厢空气的效果&#xff0c;让整个车厢更加绿色健康&#xff0c;清新淡雅。星骏汇小许Xjh15863 产品功能&…

23款奔驰GLC260L升级原厂540全景影像 高清环绕的视野

嗨 今天给大家介绍一台奔驰GLC260L升级原厂360全景影像 新款GLC升级原厂360全景影像 也只需要安装前面 左右三个摄像头 后面的那个还是正常用的&#xff0c;不过不一样的是 升级完成之后会有多了个功能 那就是新款透明底盘&#xff0c;星骏汇小许Xjh15863 左右两边只需要更换后…

计算机毕业设计-------基于JSP+Servlet的毕业生离校管理系统

需求分析 使用JSPServletMysql技术设计一个毕业生离校管理系统, 整个系统采用BS架构, 为高校方便进行毕业生离校流程进行统一的离校流程, 极大的减少了大量学生同时离校的过程中杂乱的情况, 整个系统分为学生, 教务处, 辅导员, 图书馆, 宿管, 财务处, 系办公室, 管理员登等角色…

SpringBoot整合mybatis多数据源

废话不多说先上结果 对应数据库 首先导入所需的mybatis、mysql和lombok依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependen…

win11电脑图形卡不支持或已禁用硬件加速怎么解决,N卡GPU看不到cuda进程怎么办

摘要 亲&#xff0c;很高兴为你解答。win11电脑图形卡不支持或已禁用硬件加速解决方法&#xff1a;1、点击任务栏上的开始图标&#xff0c;在打开的菜单中&#xff0c;点击设置&#xff0c;&#xff08;快捷键WINX&#xff0c;点击设置&#xff09;。2、Windows系统 设置窗口&a…

Vite scss 如何引入本地 字体

Vite scss 如何引入本地 字体 最近在用 Vite 改造一个旧项目 Diary&#xff0c;遇到了好多从 Vue 转到 Vite 的问题。 这次这个问题是&#xff1a; scss 里本地字体引入的问题。 一、问题描述 可以看到下面的卡片字体&#xff0c;本来应该是 impact 的&#xff0c;但现在无法…

学习笔记之——NeRF SLAM(基于神经辐射场的SLAM)

NeRF SLAM&#xff08;Neural Radiance Fields Simultaneous Localization and Mapping&#xff09;是一种结合神经辐射场&#xff08;NeRF&#xff09;和SLAM&#xff08;Simultaneous Localization and Mapping&#xff09;的先进技术&#xff0c;用于实时地构建三维环境地图…