C++游戏服务器框架笔记(五)_封装Epoll

C++游戏服务器框架笔记(一)_封装数据包类

C++游戏服务器框架笔记(二)_封装Socket类

C++游戏服务器框架笔记(三)_封装ByteBuffer类

C++游戏服务器框架笔记(四)_封装Select

C++游戏服务器框架笔记(五)_封装Epoll类 

        在上一文中已经介绍了,为了将Windows下的select()和linux下的epoll()封装为统一接口,所以需要首先定义一个接口类,来约定统一接口和一些类型,做到不同平台,调用接口一致,内部实现根据平台不同的跨平台效果,并给出了接口类的实现,这里为了方便阅读,再贴一遍代码:

统一接口类(多路复用基类):

#ifndef __POLLBASE_H_
#define __POLLBASE_H_#include <stdlib.h>
#include <map>
#include <vector>//统一描述符的类型命名,都为SOCKET
#ifndef _WIN32
typedef int SOCKET;
#define INVALID_HANDLE_VALUE (-1)
#endif//重定义Windows下FD_SETSIZE的大小
#ifdef _WIN32
#define FD_SETSIZE 1024
#include <WinSock2.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sys/select.h>
#endif#define MAXEVENT 1024//统一定义Windows下select()和linux下epoll()的事件的宏
#define NONE 0                        //无
#define POLLREAD 1                    //读事件
#define POLLWRITE 2                   //写事件
#define POLLET 3                      //边缘触发(用于EPOLL, 是否设置边缘触发,默认是水平触发)//定义统一的事件结构
typedef struct PollEvent {int event;int fd;
}PollEvent;//接口类(抽象类)
class PollBase
{
public:virtual ~PollBase() {};/*创建(初始化)接口size: 可关注的描述符数量返回值:0:     成功-1:     失败*/virtual int Create(int size) = 0;/*为fd描述符添加关注的事件fd:     socket文件描述符mask:   上面统一定义的事件宏(读事件、写事件)返回值:0:     成功-1:     失败*/virtual int AddEvent(SOCKET fd, int mask) = 0;/*删除fd描述符关注的事件fd:     socket文件描述符mask:   上面统一定义的事件宏(读事件、写事件)返回值:0:     成功-1:     失败*/virtual int DelEvent(SOCKET fd, int mask) = 0;/*监听事件到来,IO多路复用的核心active_events: 输出参数,如果有事件到来,则会将事件设置到active_events输出timeout:        超时时间(秒)返回值:0:无事件>0:到来事件的数量*/virtual int Poll(PollEvent* active_events, int timeout = 0) = 0;
};#endif

Epoll.h文件中定义Epoll类继承自PollBase

#ifndef _EPOLL_H_
#define _EPOLL_H_#include "PollBase.h"
#ifndef _WIN32class Epoll :public PollBase
{
public:~Epoll();int Create(int size);int AddEvent(SOCKET fd, int event);int DelEvent(SOCKET fd, int event);int Poll(PollEvent* active_events, int timeout = 0);private://epoll文件描述符(epoll实例句柄,epoll_create()的返回值)int m_EpollFd;//epoll事件数量int m_EventSize;//epoll fd对应关注事件(POLLREAD、POLLWRITE、POLLET)映射表std::map<SOCKET, int> m_EventMap;//存储到来的临时事件列表std::vector<struct epoll_event> m_Events;
};
#endif#endif

Epoll.cpp

#include "Epoll.h"
#ifndef _WIN32//析构函数中清理数据
Epoll::~Epoll() {m_Events.clear();m_Events.shrink_to_fit();m_EventMap.clear();//关闭epoll文件描述符if (m_EpollFd != -1)close(m_EpollFd);
}//创建多路IO
int Epoll::Create(int size) {m_EventSize = size;m_Events.resize(m_EventSize);//创建epollm_EpollFd = epoll_create(size);if (-1 == m_EpollFd) {return -1;}m_EventMap.clear();return 0;
}//增加关注事件
int Epoll::AddEvent(SOCKET fd, int event) {//临时存储旧的关注事件int old_event = m_EventMap[fd];//存储新的关注事件int new_event = m_EventMap[fd];//判断添加可读事件(|=表示不删除原来关注的事件的前提下,增加关注新的事件)if (event & POLLREAD) {new_event |= EPOLLIN;}//判断添加可写事件if (event & POLLWRITE) {new_event |= EPOLLOUT;}//判断设置边缘触发模式(默认是水平触发模式)if (event & POLLET){new_event |= EPOLLET;}//更新socketfd对应的事件m_EventMap[fd] = new_event;//创建新的epoll事件结构,赋值新的关注事件struct epoll_event ev;ev.events = new_event;ev.data.fd = fd;//old_event>0表示该fd之前有在epoll中关注过其他事件,所以这里应该是使用修改更新事件的模式,//否则应该使用添加新事件的模式int ctl_mode = old_event > 0 ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;if (-1 == epoll_ctl(m_EpollFd, ctl_mode, fd, &ev)) {return -1;}return 0;
}//移除关注的事件 (基本逻辑同添加)
int Epoll::DelEvent(SOCKET fd, int event) {int old_event = m_EventMap[fd];int new_event = old_event;if (event & POLLREAD) {new_event ^= EPOLLIN;}if (event & POLLWRITE) {new_event ^= EPOLLOUT;}m_EventMap[fd] = new_event;struct epoll_event ev;ev.events = new_event;ev.data.fd = fd;int ctl_mode = ev.events > 0 ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;if (-1 == epoll_ctl(m_EpollFd, ctl_mode, fd, &ev)) {return -1;}return 0;
}//事件分发
int Epoll::Poll(PollEvent* active_events, int timeout) {  //epoll_wait 等待关注的事件到来//当新事件到来时,会将到来的事件写入m_Events数组int num = epoll_wait(m_EpollFd, &m_Events[0], m_EventSize, timeout);//num<=0 表示无事件到来,不作处理(本系列统一使用非阻塞套接字,因此当没有事件的时候,num一般都为0)if (num <= 0)return 0;//当有事件到来时,num则是到来的事件数量,遍历m_Events事件数组处理各个事件for (int i = 0; i < num; i++) {int event = 0;//可读事件if (m_Events[i].events & EPOLLIN) {event |= POLLREAD;}//可写事件if (m_Events[i].events & EPOLLOUT) {event |= POLLWRITE;}//将事件信息赋值给输出参数active_events数组active_events[i].fd = m_Events[i].data.fd;active_events[i].event = event;}//返回事件数量return num;
}
#endif

封装后的大概调用流程,和前文的Select接口调用代码一致:

......void EventLoop::Run() {while (!m_Stop) {memset(m_ActiveEvents, 0, m_Size);int num = m_Poll->Poll(m_ActiveEvents);if (num > 0) {//分发事件进行处理this->ActiveEvents(num);}}
}......

经过前面各类基础类的封装,到现在封装之后,接下来就是对各个事件的处理,处理各个tcp连接,以及在数据的流转,最后和上层调用者的交互了。

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

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

相关文章

数据结构——单链表OJ题(第二弹)

单链表OJ题 前言一、返回链表开始入环的第一个节点思路一思路二 二、返回链表的深度拷贝总结 前言 此次练习题有两道&#xff01; 有点小难度&#xff0c;但相信难不住大家的&#xff01; 我也会给出两道OJ题的链接&#xff0c;大家也赶快去试一试吧 一、返回链表开始入环的第…

实验3-11 计算油费 (15 分)

实验3-11 计算油费 &#xff08;15 分&#xff09; 现在90号汽油6.95元/升、93号汽油7.44元/升、97号汽油7.93元/升。为吸引顾客&#xff0c;某自动加油站推出了“自助服务”和“协助服务”两个服务等级&#xff0c;分别可得到5%和3%的折扣。 本题要求编写程序&#xff0c;根据…

【网络基础进阶之路】基于MGRE多点协议的实战详解

PS&#xff1a;本要求基于华为的eNSP模拟软件进行 具体要求&#xff1a; 完成步骤&#xff1a; 1、根据上述要求&#xff0c;对各路由器进行地址安排&#xff0c;如下图。 2、进入各路由器&#xff0c;对每个端口进行地址设置。 R1路由器设置&#xff1a; ISP路由器设置&…

Go如何构建高效API接口| 青训营

Go语言作为一个高效的静态类型语言&#xff0c;在构建API服务时也表现出了很大的优势。本文将介绍如何使用Go语言构建高效的API服务&#xff0c;帮助开发者更好地应对日益增长的API需求。 一、选择适合的框架 首先&#xff0c;选择适合的框架是构建高效API服务的重要一步。在…

淘宝资源采集(从零开始学习淘宝数据爬取)

1. 为什么要进行淘宝数据爬取&#xff1f; 淘宝数据爬取是指通过自动化程序从淘宝网站上获取数据的过程。这些数据可以包括商品信息、销售数据、评论等等。淘宝数据爬取可以帮助您了解市场趋势、优化您的产品选择以及提高销售额。 淘宝作为全球的电商平台&#xff0c;每天都有…

flutter:占位视图(骨架屏、shimmer)

前言 有时候打开美团&#xff0c;在刚加载数据时会显示一个占位视图&#xff0c;如下&#xff1a; 那么这个是如何实现的呢&#xff1f;我们可以使用shimmer来开发该功能 实现 官方文档 https://pub-web.flutter-io.cn/packages/shimmer 安装 flutter pub add shimmer示例…

2023年08月在线IDE流行度最新排名

点击查看最新在线IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年08月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相…

使用Vscode编辑keil工程

一、需要安装的插件 1. Keil Assistant 2. C/C 3. 中文配置&#xff1a; 二、插件配置 1. Keil Assistant 添加Keil的安装路径 接下来就可以使用vscode编辑Keil的工程了&#xff0c;调试编译和下载程序需要返回到Keil中进行操作。 三、Vscode常用快捷键 可以自定义进行配置…

【雷达通信】非相干多视处理(CSA)(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

echarts绘制关系图

效果图&#xff1a; 代码&#xff1a; <template><div id"serveGraph" style"height: 100%; width: 100%; z-index: 88;"></div> </template> <script> import { defineComponent,reactive,toRefs,onMounted,watch } from …

MFC、Qt、WPF?该用哪个?

MFC、Qt和WPF都是流行的框架和工具&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序。选择哪个框架取决于你的具体需求和偏好。MFC&#xff08;Microsoft Foundation Class&#xff09;是微软提供的框架&#xff0c;使用C编写&#xff0c;主要用于Windows…

Vue2:基础入门

Vue2&#xff1a;基础入门1 Date: April 10, 2023 Sum: vue简介、vue的基本使用、vue的指令、修饰符、过滤器&#xff08;废&#xff09;、小黑的书架、记事本 Tags: * 目标&#xff1a; 能够知道 vue 的基本使用步骤 掌握插值表达式和 v-bind 指令的用法 能够掌握如何使用…

贪心算法求解背包问题

贪心算法&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;算法得到的是在某种意义上的局部最优解 。 解题的一般步骤是&#xff1a; 1.建立数学模型来描述问题&#xff1b; 2.把求解的问题分成…

vue+ts 错误随笔

笔记 问题Parameter ‘xxx’ implicitly has an ‘any’ type的解决ts ref定义数组&#xff0c;数组遍历报错>类型“never”上不存在属性“xx”ts项目computed定义数据Getting a value from the props in root scope of <script setup> will cause the value to lose …

右值引用带来的效率提升(C++11)

文章目录 一.左值引用和右值引用二.C11区分左值和右值的语法设计意义--对象的移动构造和移动赋值场景分析1:C11之前C11之后 场景分析2:函数std::move右值引用的广泛使用 三.引用折叠 一.左值引用和右值引用 左值:可以取到地址的对象(可以出现在赋值符号的左边),对左值的引用称…

【Linux】计算机网络的背景和协议分层

文章目录 网络发展协议何为协议网络协议协议分层OSI七层模型TCP/IP五层模型&#xff08;四层&#xff09; 基本通信流程mac地址和ip地址网络通信本质 网络发展 从一开始计算机作为一台台单机使用&#xff0c;到现在网络飞速发展&#xff0c;从局域网Lan建立起局域网&#xff0…

go逆向符号恢复

前言 之前一直没怎么重视&#xff0c;结果发现每次遇到go的题都是一筹莫展&#xff0c;刷几道题练习一下吧 准备 go语言写的程序一般都被strip去掉符号了&#xff0c;而且ida没有相关的签名文件&#xff0c;没办法完成函数名的识别与字符串的定位&#xff0c;所以第一步通常…

时序数据异常检测算法

引言 异常检测的场景很多&#xff0c;例如&#xff1a;硬件的故障检测、流量的异常点的检测等场景。针对时间序列类数据的异常检测算法也有很多&#xff0c;业界比较流行的比如普通的统计学习方法–3σ原则和箱线图识别数据离群点&#xff0c;它利用检测点偏移量来检测出异常。…

【八】mybatis 日志模块设计

mybatis 日志模块设计 简介&#xff1a;闲来无事阅读一下mybatis的日志模块设计&#xff0c;学习一下优秀开源框架的设计思路&#xff0c;提升自己的编码能力 模块设计 在Mybatis内部定义了4个级别&#xff1a;Error:错误 、warn:警告、debug:调试、trance&#xff0c;日志优…

HDFS架构刨析

HDFS架构刨析 概述HDFS架构图整体概述主角色&#xff1a;namenodefsimage内存元数据镜像文件edits log&#xff08;Journal&#xff09;编辑日志 从角色&#xff1a;datanode主角色辅助角色&#xff1a;secondarynamenode 重要特性主从架构分块存储机制副本机制namespace元数据…