30天自制C++服务器day05-epoll高级用法-Channel登场

2023-05-16

在上一天,我们已经完整地开发了一个echo服务器,并且引入面向对象编程的思想,初步封装了SocketInetAddressEpoll,大大精简了主程序,隐藏了底层语言实现细节、增加了可读性。

让我们来回顾一下我们是如何使用epoll:将一个文件描述符添加到epoll红黑树,当该文件描述符上有事件发生时,拿到它、处理事件,这样我们每次只能拿到一个文件描述符,也就是一个int类型的整型值。试想,如果一个服务器同时提供不同的服务,如HTTP、FTP等,那么就算文件描述符上发生的事件都是可读事件,不同的连接类型也将决定不同的处理逻辑,仅仅通过一个文件描述符来区分显然会很麻烦,我们更加希望拿到关于这个文件描述符更多的信息。

在day03介绍epoll时,曾讲过epoll_event结构体:

typedef union epoll_data {
  void *ptr;
  int fd;
  uint32_t u32;
  uint64_t u64;
} epoll_data_t;
struct epoll_event {
  uint32_t events;	/* Epoll events */
  epoll_data_t data;	/* User data variable */
} __EPOLL_PACKED;

可以看到,epoll中的data其实是一个union类型,可以储存一个指针。而通过指针,理论上我们可以指向任何一个地址块的内容,可以是一个类的对象,这样就可以将一个文件描述符封装成一个Channel类,一个Channel类自始至终只负责一个文件描述符,对不同的服务、不同的事件类型,都可以在类中进行不同的处理,而不是仅仅拿到一个int类型的文件描述符。

这里读者务必先了解C++中的union类型,在《C++ Primer(第五版)》第十九章第六节有详细说明。

Channel类的核心成员如下:

class Channel{
private:
    Epoll *ep;
    int fd;
    uint32_t events;
    uint32_t revents;
    bool inEpoll;
};

显然每个文件描述符会被分发到一个Epoll类,用一个ep指针来指向。类中还有这个Channel负责的文件描述符。另外是两个事件变量,events表示希望监听这个文件描述符的哪些事件,因为不同事件的处理方式不一样。revents表示在epoll返回该Channel时文件描述符正在发生的事件。inEpoll表示当前Channel是否已经在epoll红黑树中,为了注册Channel的时候方便区分使用EPOLL_CTL_ADD还是EPOLL_CTL_MOD

接下来以Channel的方式使用epoll:
新建一个Channel时,必须说明该Channel与哪个epollfd绑定:

Channel *servChannel = new Channel(ep, serv_sock->getFd());

这时该Channel还没有被添加到epoll红黑树,因为events没有被设置,不会监听该Channel上的任何事件发生。如果我们希望监听该Channel上发生的读事件,需要调用一个enableReading函数:

servChannel->enableReading();

调用这个函数后,如Channel不在epoll红黑树中,则添加,否则直接更新Channel、打开允许读事件。enableReading函数如下:

void Channel::enableReading(){
    events = EPOLLIN | EPOLLET;
    ep->updateChannel(this);
}

可以看到该函数做了两件事,将要监听的事件events设置为读事件并采用ET模式,然后在ep指针指向的Epoll红黑树中更新该ChannelupdateChannel函数的实现如下:

void Epoll::updateChannel(Channel *channel){
    int fd = channel->getFd();  //拿到Channel的文件描述符
    struct epoll_event ev;
    bzero(&ev, sizeof(ev));
    ev.data.ptr = channel;
    ev.events = channel->getEvents();   //拿到Channel希望监听的事件
    if(!channel->getInEpoll()){
        errif(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1, "epoll add error");//添加Channel中的fd到epoll
        channel->setInEpoll();
    } else{
        errif(epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1, "epoll modify error");//已存在,则修改
    }
}

在使用时,我们可以通过Epoll类中的poll()函数获取当前有事件发生的Channel

while(true){
    vector<Channel*> activeChannels = ep->poll();
    // activeChannels是所有有事件发生的Channel
}

注:在今天教程的源代码中,并没有将事件处理改为使用Channel回调函数的方式,仍然使用了之前对文件描述符进行处理的方法,这是错误的,将在明天的教程中进行改写。

至此,day05的主要教程已经结束了,完整源代码请在code/day05文件夹。服务器的功能和昨天一样,添加了Channel类,可以让我们更加方便简单、多样化地处理epoll中发生的事件。同时脱离了底层,将epoll、文件描述符和事件进行了抽象,形成了事件分发的模型,这也是Reactor模式的核心,将在明天的教程进行讲解。

进入code/day05文件夹,使用make命令编译,将会得到serverclient,输入命令./server开始运行服务器。然后在一个新终端输入命令./client运行客户端,可以看到服务器接收到了客户端的连接请求,并成功连接。再新开一个或多个终端,运行client,可以看到这些客户端也同时连接到了服务器。此时我们在任意一个client输入一条信息,服务器都显示并发送到该客户端。如使用control+c终止掉某个client,服务器回显示这个client已经断开连接,但其他client并不受影响。

完整源代码:https://github.com/yuesong-feng/30dayMakeCppServer/tree/main/code/day05

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

30天自制C++服务器day05-epoll高级用法-Channel登场 的相关文章

  • OpenSSL简介及在Windows、Linux、Mac系统上的编译步骤

    OpenSSL介绍 xff1a OpenSSL是一个强大的安全套接字层密码库 xff0c 囊括主要的密码算法 常用的密钥和证书封装管理功能及SSL协议 xff0c 并提供丰富的应用程序供测试或其它目的使用 SSL是SecureSockets
  • 信息安全领域相关术语介绍

    一 SSL 安全套接字层 SSL Secure Sockets Layer 是一种协议 xff0c 支持服务通过网络进行通信而不损害安全性 它在客户端和服务器之间创建一个安全连接 然后通过该连接安全地发送任意数据量 SSL最初是用来保障数据
  • 对称加密算法之DES介绍

    DES Data Encryption Standard 是分组对称密码算法 DES采用了64位的分组长度和56位的密钥长度 xff0c 它将64位的输入经过一系列变换得到64位的输出 解密则使用了相同的步骤和相同的密钥 DES的密钥长度为
  • OpenSSL中对称加密算法DES常用函数使用举例

    主要包括3个文件 xff1a 1 cryptotest h ifndef CRYPTOTEST H define CRYPTOTEST H include lt string gt using namespace std typedef e
  • 对称加密算法之RC4介绍及OpenSSL中RC4常用函数使用举例

    RC4是一种对称密码算法 xff0c 它属于对称密码算法中的序列密码 streamcipher 也称为流密码 xff0c 它是可变密钥长度 xff0c 面向字节操作的流密码 RC4是流密码streamcipher中的一种 xff0c 为序列
  • 摘要算法之MD5介绍及OpenSSL中MD5常用函数使用举例

    MD5 Message DigestAlgorithm 5 是计算机中广泛使用的杂凑算法之一 主要可以实现将数据运算后转换为一串固定值 xff0c 其前身主要有MD2 MD3和MD4算法 MD2算法在1989年由Rivest设计开发 xff
  • 非对称加密算法之RSA介绍及OpenSSL中RSA常用函数使用举例

    RSA算法 xff0c 在1977年由Ron Rivest Adi Shamirh和LenAdleman xff0c 在美国的麻省理工学院开发完成 这个算法的名字 xff0c 来源于三位开发者的名字 RSA已经成为公钥数据加密标准 RSA属
  • 有效的rtsp流媒体测试地址汇总

    以下是从网上搜集的一些有效的rtsp流媒体测试地址 xff1a 1 rtsp 218 204 223 237 554 live 1 0547424F573B085C gsfp90ef4k0a6iap sdp 2 rtsp 218 204 2
  • Flask【第十章】:特殊装饰器 @app.before_request 和 @app.after_request 以及@app.errorhandler...

    特殊装饰器 64 app before request 和 64 app after request以及 64 app errorhandler 一 背景 xff1a Flask我们已经学习很多基础知识了 现在有一个问题 我们现在有一个 F
  • Linux Socket基础介绍

    Linux Socket函数库是从Berkeley大学开发的BSD UNIX系统中移植过来的 BSD Socket接口是众多Unix系统中被广泛支持的TCP IP通信接口 xff0c Linux下的Socket程序设计 xff0c 除了微小
  • libcurl库的使用(通过libcurl库下载url图像)

    1 从http curl haxx se download html下载libcurl源码 xff0c 解压缩 xff1b 2 通过CMake cmake gui 生成vs2013 x64位 CURL sln xff1b 3 打开CURL
  • 人工神经网络简介

    本文主要对人工神经网络基础进行了描述 xff0c 主要包括人工神经网络的概念 发展 特点 结构 模型 本文是个科普文 xff0c 来自网络资料的整理 一 人工神经网络的概念 人工神经网络 xff08 Artificial Neural Ne
  • 卷积神经网络(CNN)基础介绍

    本文是对卷积神经网络的基础进行介绍 xff0c 主要内容包括卷积神经网络概念 卷积神经网络结构 卷积神经网络求解 卷积神经网络LeNet 5结构分析 卷积神经网络注意事项 一 卷积神经网络概念 上世纪60年代 xff0c Hubel等人通过
  • C++中struct的使用

    C 43 43 语言继承了C语言的struct xff0c 并且加以扩充 在C语言中struct是只能定义数据成员 xff0c 而不能定义成员函数的 而在C 43 43 中 xff0c struct类似于class xff0c 在其中既可以
  • Windows与Linux之间互传文件的方法

    以下方法均是以Windows为操作机 xff1a 1 通过WinSCP WinSCP是一款开源的SFTP客户端 xff0c 运行于Windows系统下 xff0c 遵照GPL发布 WinSCP除了SFTP xff0c 还支持SSH SCP
  • 非对称加密算法RSA公钥私钥的模数和指数提取方法

    生成非对称加密算法RSA公钥 私钥的方法 xff1a 1 通过OpenSSL库生成 xff0c 可参考 https github com fengbingchun OpenSSL Test blob master demo OpenSSL
  • Base64简介

    Base64是一种基于64个可打印字符来表示二进制数据的表示方法 由于2 6 61 64 xff0c 所以每6个比特为一个单元 xff0c 对应某个可打印字符 3个字节有24个比特 xff0c 对应于4个Base64单元 xff0c 即3个
  • HTTP协议简介

    HTTP HyperText Transfer Protocol 超文本传输协议 xff1a 是一种用于分布式 协作式和超媒体信息系统的应用层协议 HTTP是万维网的数据通信的基础 设计HTTP最初的目的是为了提供一种发布和接收HTML页面
  • HTTPS协议简介

    HTTPS HyperText Transfer Protocol Secure 超文本传输安全协议 xff1a 是一种透过计算机网络进行安全通信的传输协议 HTTPS经由HTTP进行通信 xff0c 但利用SSL TLS来加密数据包 HT
  • base64开源库介绍及使用

    网上有一些开源的base64编解码库的实现 xff0c 下面介绍几个 xff1a cppcodec是一个仅包括头文件的C 43 43 11库 xff0c 用于编解码RFC 4648中指定的base64 base64url base32 ba

随机推荐

  • Ubuntu下使用CMake编译OpenSSL源码操作步骤(C语言)

    OpenSSL的版本为1 0 1g xff0c 在ubuntu下通过CMake仅编译c代码不包括汇编代码 xff0c 脚本内容如下 xff1a build sh内容 xff1a bin bash real path 61 realpath
  • ImageNet图像数据集介绍

    ImageNet图像数据集始于2009年 xff0c 当时李飞飞教授等在CVPR2009上发表了一篇名为 ImageNet A Large Scale Hierarchical Image Database 的论文 xff0c 之后就是基于
  • 网络文件系统(NFS)简介

    网络文件系统 Network File System NFS 是一种分布式文件系统协议 xff0c 最初由Sun Microsystems公司开发 xff0c 并于1984年发布 其功能旨在允许客户端主机可以像访问本地存储一样通过网络访问服
  • 实时流协议(RTSP)简介

    RTSP Real Time Streaming Protocol xff0c RFC2326 xff0c 实时流传输协议 xff0c 是TCP IP协议体系中的一个应用层协议 xff0c 由哥伦比亚大学 网景 Netscape 和Real
  • 远程过程调用RPC简介

    RPC Remote Procedure Call 远程过程调用 xff1a 是一种通过网络从远程计算机程序上请求服务 xff0c 而不需要了解底层网络技术的思想 RPC是一种技术思想而非一种规范或协议 xff0c 常见RPC技术和框架有
  • C语言中头文件包含的处理原则

    很多事不深入以为自己懂了 xff0c 但真正用到项目上 xff0c 才发现了问题 曾以为自己写C语言已经轻车熟路了 xff0c 特别是对软件文件的工程管理上 xff0c 因为心里对自己的代码编写风格还是有自信的 毕竟刚毕业时老大对我最初的训
  • Unity3D物体自动躲避障碍物

    Unity版本 2017 4 4f1 基本思路 物体向前发射一个射线 xff0c 检测到碰撞后 xff0c 根据碰撞信息选择新的方向 最终结果如下 具体实现步骤代码 1 物体添加胶囊体碰撞组件CapsuleCollider 通过发射虚拟胶囊
  • nginx的请求接收流程(二)

    在ngx http process request line函数中 xff0c 解析完请求行之后 xff0c 如果请求行的uri里面包含了域名部分 xff0c 则将其保持在请求结构的headers in成员的server字段 xff0c h
  • C++学习_udp协议(socket)的封装

    C 43 43 学习笔记 xff0c UDP socket 协议的封装实现 1 配置QT下的pro文件 1 TEMPLATE 61 app 2 CONFIG 43 61 console 3 CONFIG 61 app bundle 4 CO
  • 西门子PLC学习笔记一(S7-300简介)

    使用了Step7有几天了 xff0c 现在系统的学习一下 xff0c 现记录一下学习的内容 1 S7 300硬件结构 S7 300或者S7 400的PLC是模块式的PLC xff0c 各种模块式相互独立的 xff0c 分别安装在机架上 硬件
  • 外网访问树莓派服务器(自购域名+Sakura Frp内网穿透)

    首先在域名代理商 xff08 如腾讯云 xff09 购买一个喜欢的域名 注册Sakura Frp账号 xff0c 进入管理面板后 xff0c 创建隧道 xff0c 服务器选择可建站类型的 xff0c 隧道类型为HTTP xff0c 本地地址
  • Python删除全部已安装的pip包

    pip freeze span class token operator gt span allpackages txt pip uninstall r allpackages txt y
  • Vue父组件主动获取子组件的值和方法

    在父组件使用子组件的代码中 xff0c 为子组件加上ref 61 34 name 自己设置一个名称 34 然后在代码中 xff1a span class token keyword this span span class token pu
  • 动态规划详解

    动态规划的入门 xff0c 一般是从斐波拉契数列开始 该数列由0和1开始 xff0c 后面的每一项数字都是前面两项数字的和 xff0c 定义如下 xff1a F 0 61 0 F 1 61 1 F n 61 F n 1 43 F n 2 其
  • Concept Whitening(for Interpretable Image Recognition)

    和BatchNorm相比有很多优点 xff0c 并且可以直接替换BatchNorm 有更好的interpretability xff08 可解释性 xff09 xff0c 可以可视化得解释神经网络层的含义 xff08 这是最突出的特点 xf
  • homebrew安装、换源

    首先确认你的Mac已经安装了命令行工具 xff1a Command Line Tools CLT for Xcode 打开终端 xff0c 输入git version xff0c 命令 xff0c 如果没有安装 xff0c macOS会跳出
  • macOS查看磁盘读写数据总量、磁盘健康、磁盘启动次数等信息

    首先确保安装了homebrew xff0c 如果没有安装可以按照这篇文章的教程安装 xff1a homebrew安装 换源 然后安装磁盘工具smartmontools brew span class token function insta
  • 30天自制C++服务器

    30天自制C 43 43 服务器 如访问慢 xff0c 可以到这里观看 xff1a csblog 教程的配套网络库 xff1a pine xff0c star and fork 先说结论 xff1a 不管使用什么语言 xff0c 一切后台开
  • 【C语言】之实现 printf 函数功能

    span class token comment 文件名 myPrintf c 文件功能 使用putchar函数模拟printf函数的功能 编辑人 王廷云 编辑时间 2017 10 14 修改时间 2018 1 12 span span c
  • 30天自制C++服务器day05-epoll高级用法-Channel登场

    在上一天 xff0c 我们已经完整地开发了一个echo服务器 xff0c 并且引入面向对象编程的思想 xff0c 初步封装了Socket InetAddress和Epoll xff0c 大大精简了主程序 xff0c 隐藏了底层语言实现细节