muduo网络库剖析——通道Channel类

muduo网络库剖析——通道Channel类

  • 前情
    • 从muduo到my_muduo
  • 概要
    • 事件种类
    • channel
  • 框架与细节
    • 成员
    • 函数
    • 细节实现
    • 使用方法
  • 源码
  • 结尾

前情

从muduo到my_muduo

作为一个宏大的、功能健全的muduo库,考虑的肯定是众多情况是否可以高效满足;而作为学习者,我们需要抽取其中的精华进行简要实现,这要求我们足够了解muduo库。

做项目 = 模仿 + 修改,不要担心自己学了也不会写怎么办,重要的是积累,学到了这些方法,如果下次在遇到通用需求的时候你能够回想起之前的解决方法就够了。送上一段话!

在这里插入图片描述

概要

事件种类

epoll_event是Linux操作系统中的一个数据结构,用于表示一个I/O事件。它在使用epoll多路复用技术时作为参数传递给相关的函数,以便在事件发生时通知应用程序。
epoll_event结构体的定义如下:

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

其中,events表示事件,例如EPOLLIN(需要读取数据的情况)、EPOLLOUT(输出缓冲为空,可以立即发送数据的情况)等。data是用户数据变量,可以使用union epoll_data来定义,其中ptr可以指向任何类型的用户数据,fd表示文件描述符,u32和u64分别表示一个32位和64位的无符号整数。

当应用程序注册了某个文件描述符到一个epoll实例上时,就可以通过epoll_event结构体来指定对应的事件以及关联的用户数据。当这些事件发生时,epoll系统调用会返回对应的epoll_event结构体,以便应用程序处理事件。

总的来说,epoll_event结构体是Linux系统中实现事件驱动编程的一个关键数据结构,通过它可以将多个I/O事件集中处理,提高了程序的效率和响应性。

channel

而channel和event一一映射,通过channel能够获取到event中的events,即感兴趣的事件,通过channel也可以改变events感兴趣的事件。同时Poller监听,如果有事件发生,那么该事件所对应channel也会调用所相应发生事件的回调函数。这就是channel类的主要作用,起到了一个代表event,但大于event作用的这样一个类。

框架与细节

成员

在这里插入图片描述
channel中成员包括自己所属的事件循环,还有channel对应的套接字,用来监听;以及该channel中event所感兴趣的事件,和真正监听到的事件,以及channel此时在Poller中处于什么状态,对应着Poller是否在监听对应的event.
在这里插入图片描述
代表感兴趣事件的类型。设为static变量,类使用。
在这里插入图片描述
以及相关的函数回调。

函数

包括一系列的函数调用声明,以及读写事件的确认与设置,感兴趣事件对应event修改,事件发生时对应回调函数触发。完成channel的与event对应,以及channel能够作为触发对象针对event监听到的事件进行函数回调触发等功能。

细节实现

如果h文件中不会规定某类的大小,或者只用到了某类的指针,我们可以通过声明class而不是include头文件的来减少头文件信息的暴露。比如:
当中的EventLoop类在h文件中只涉及指针,更多细节在cc文件中实现。那我们在头文件中只写class EventLoop;而在cc文件中再包含上EventLoop.h即可。
在这里插入图片描述
在这里插入图片描述
update函数和remove函数表示着通道的更新和删除,我们统一的实现是在时间循环类EventLoop趋势线这两个函数,所以channel和Poller中的对通道的更改会调用EventLoop类中的对channel更改函数。

使用方法

源码

//Channel.h
#pragma once#include <functional>
#include <sys/epoll.h>#include "noncopyable.h"
#include "Timestamp.h"
#include "Log.h"class EventLoop;  class Channel : noncopyable {
public:using EventCallback = std::function<void()>;using ReadEventCallback = std::function<void(Timestamp)>;Channel(EventLoop* loop, int fd) : loop_(loop), fd_(fd), events_(0), status_(0) {}~Channel() = default;int fd() const { return fd_; }EventLoop* loop() const { return loop_; }int status() const { return status_; }int events() const { return events_; }bool isReading() const { return events_ & kReadEvent; }bool isWriting() const { return events_ & kWriteEvent; }bool isNoneEvent() const { return events_ == kNoneEvent; }void enableReading() { events_ |= kReadEvent; update(); }void enableWriting() { events_ |= kWriteEvent; update(); }void disableReading() { events_ &= ~kReadEvent; update(); }void disableWriting() { events_ &= ~kWriteEvent; update(); }void disableAll() { events_ = kNoneEvent; update(); }void setReadCallback(const ReadEventCallback& cb) { readCallback_ = cb; }void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; }void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; }void setCloseCallback(const EventCallback& cb) { closeCallback_ = cb; }void remove();void set_revents(int revents) { revents_ = revents; }void set_status(int status) { status_ = status; }void handleEventWithGuard(Timestamp receiveTime);
private:void update();EventLoop* loop_;int fd_;int events_;int revents_;int status_;static const int kNoneEvent;static const int kReadEvent;static const int kWriteEvent;EventCallback writeCallback_;EventCallback errorCallback_;EventCallback closeCallback_;ReadEventCallback readCallback_;
};//Channel.cc
#include "Channel.h"
#include "EventLoop.h"void Channel::update() {loop_->updateChannel(this);
}void Channel::remove() {loop_->removeChannel(this);
}void Channel::handleEventWithGuard(Timestamp receiveTime) {LOG_INFO("%s--%s--%d : channel handle revents : %d\n", __FILE__, __FUNCTION__, __LINE__, revents_);if ((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) {if (closeCallback_) closeCallback_();}else if (revents_ & EPOLLERR) {if (errorCallback_) errorCallback_();}else if (revents_ & EPOLLIN) {if (readCallback_) readCallback_(receiveTime);}else if (revents_ & EPOLLOUT) {if (writeCallback_) writeCallback_();}
}

结尾

以上就是通道Channel类的相关介绍,以及我在进行项目重写的时候遇到的一些问题,和我自己的一些心得体会。发现写博客真的会记录好多你的成长,而且对于一个好的项目,写博客也是证明你确实有过深度思考,并且在之后面试或者工作时遇到同样的问题能够进行复盘的一种有效的手段。所以,希望uu们也可以像我一样,养成写博客的习惯,逐渐脱离菜鸡队列,向大佬前进!!!加油!!!

也希望我能够完成muduo网络库项目的深度学习与重写,并在功能上能够拓展。也希望在完成这个博客系列之后,能够引导想要学习muduo网络库源码的人,更好地探索这篇美丽繁华的土壤。致敬chenshuo大神!!!

鉴于博主只是一名平平无奇的大三学生,没什么项目经验,所以可能很多东西有所疏漏,如果有大神发现了,还劳烦您在评论区留言,我会努力尝试解决问题!

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

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

相关文章

tui.calender日历创建、删除、编辑事件、自定义样式

全是坑&#x1f573;&#xff01;全是坑&#x1f573;&#xff01;全是坑&#x1f573;&#xff01;能不用就不用&#xff01; 官方文档&#xff1a;https://github.com/nhn/tui.calendar/blob/main/docs/en/apis/calendar.md 实例的一些方法&#xff0c;比如创建、删除、修改、…

大数据平台的硬件规划、网络调优、架构设计、节点规划

1.大数据平台硬件选型 要对Hadoop大数据平台进行硬件选型,首先需要了解Hadoop的运行架构以及每个角色的功能。在一个典型的Hadoop架构中,通常有5个角色,分别是NameNode、Standby NameNode、ResourceManager、NodeManager、DataNode以及外围机。 其中 NameNode 负责协调集群…

用git bash调用md5sum进行批量MD5计算

对于非常大的文件或者很重要的文件&#xff0c;在不稳定的网络环境下&#xff0c;可能文件的某些字节会损坏。此时&#xff0c;对文件计算MD5即可以校验其完整性。比如本次的 OpenStreetMap 导出包&#xff0c;我的学弟反馈通过网盘下载无法解压&#xff0c;并建议我增加每个文…

HashMap 的底层实现#JDK1.8 之前

最近很多同学问我有没有java学习资料&#xff0c;我根据我从小白到架构师多年的学习经验整理出来了一份50W字面试解析文档、简历模板、学习路线图、java必看学习书籍 、 需要的小伙伴 可以关注我公众号&#xff1a;“ Tom聊架构 ”&#xff0c; 回复暗号&#xff1a;“ 578”即…

HCIA——18实验:NAT

学习目标&#xff1a; NAT 学习内容&#xff1a; NAT 1.要求——基本的 2.模型 3.IP分配、规划、优化 1&#xff09;思路 R2为ISP路由器&#xff0c;其上只能配置ip地址&#xff0c;不得冉进行其他的任何配置—ospf配置 认证 、汇总、沉默接口、加快收敛、缺省路由 PC1-PC2…

AIGC:人工智能驱动的数据分析新时代

AIGC&#xff1a;人工智能驱动的数据分析新时代 随着人工智能技术的迅猛发展&#xff0c;我们正迎来数据分析的新时代&#xff0c;其中AIGC&#xff08;Artificial Intelligence with Generative Capabilities&#xff09;的应用成为引领潮流的重要方向。本文将深入探讨几个关…

git中合并分支时出现了代码冲突怎么办

目录 第一章、Git代码冲突介绍1.1&#xff09;什么是Git代码冲突①git merge命令介绍②代码冲突原因 1.2&#xff09;提示代码冲突的两种情况①本地不同分支的文件有差异时&#xff1a;②本地仓库和git远程仓库的文件有差异时&#xff1a; 1.3&#xff09;解决合并时的代码冲突…

搜索经典题——填充 9*9矩阵

题目&#xff1a;给定一个九行九列矩阵&#xff0c;填充矩阵元素&#xff0c;要求&#xff1a; 1、每一行每一列&#xff0c;每个小九宫格&#xff08;图片画粗的地方就是&#xff09;不能包含相同元素 2、每一行&#xff0c;每一列&#xff0c;每个小九宫格均会完整出现1-9的数…

LeetCode.2788. 按分隔符拆分字符串

题目 题目链接 分析 题目的意思是给我们一个字符串数组和一个分隔符&#xff0c;让我们按照分隔符把字符串数组分割成新的字符串数组。 看到这个描述&#xff0c;这不就是直接就是利用 按照分隔符分割字符串的系统库函数split()&#xff0c;这个函数的意思就是 把一个字符串…

Jenkins环境配置篇-更换插件源

作为持续集成的利器 Jenkins 已经得到了广泛地应用&#xff0c;仅仅作为一个工具&#xff0c;Jenkins 已然有了 自己的生态圈&#xff0c;支持其的 plugin 更是超过 1300。在实际中如何使用以及如何更好地使用 jenkins&#xff0c;一直是大家在实践并讨论的。本系列文章将会从如…

链表回文结构

链表回文结构 编写一个函数&#xff0c;检查输入的链表是否是回文的。 示例 1&#xff1a; 输入&#xff1a; 1->2 输出&#xff1a; false 示例 2&#xff1a; 输入&#xff1a; 1->2->2->1 输出&#xff1a; true 链表的回文结构&#xff0c;应该先找到中间节…

区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 …