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

Muduo库源码剖析(一)——Channel

Muduo库源码剖析(一)——Channel

说明

本源码剖析是在muduo基础上,保留关键部分进行改写分析。

要点总结

事件分发器 event dispatcher中最重要的两个类型 channelPoller

Channel可理解为通道,poller往通道传输数据(事件发生情况)。

EventLoop包含多个channel一个 Poller

Channel相当于是对socket事件处理封装,包含了socket的详细信息,scoket以及感兴趣的事件都在channel里;

channel是muduo库负责注册读写事件的类,并保存了fd读写事件发生时调用的回调函数,如果poll/epoll有读写事件发生则将这些事件添加到对应的通道中。

  • 一个channel对应唯一EventLoop,一个EventLoop可以有多个channel

  • Channel类不负责fd的生存期,fd的生存期是由socket决定的,断开连接关闭描述符。

  • 当有fd返回读写事件时,调用提前注册的回调函数处理读写事件

  • 头文件中只给类的前置声明,而在源文件中再给出头文件包含,因为源文件会被编程动态库.so, 减少对外暴露

  • weak_ptr 用于观察绑定对象的状态,并且可以尝试提升为shared_ptr

Channel这个模块对应Reactor模型上的 Demultiplex (多路复用器)

在这里插入图片描述

重点代码详解

// Channel.h
#pragma once#include "noncopyable.h"
#include "Timestamp.h"#include <functional>
#include <memory>// 头文件中只给类的前置声明,而在源文件中再给出头文件包含
// 因为源文件会被编程动态库.so, 减少对外暴露
class EventLoop;class Channel : noncopyable
{
public:using EventCallback = std::function<void()>;using ReadEventCallback = std::function<void(Timestamp)>;Channel(EventLoop *loop, int fd);~Channel();// fd得到poller通知后调用其处理事件void handleEvent(Timestamp recevieTime);void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); }void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }// 防止当Channel的所有者被手动remove掉时,Channel 仍在执行回调void tie(const std::shared_ptr<void>&); // 检测资源存活状态int fd() const { return fd_; }int events() const { return events_; }void set_revents(int revt) { revents_ = revt; }// 设置fd相应的事件状态// enableReading 让fd对读事件感兴趣// update()底层也是调用 epoll_ctlvoid enableReading() { events_ |= kReadEvent; update(); }void disableReading() { events_ &= ~kReadEvent; update(); }void enableWriting() { events_ |= kWriteEvent; update(); }void disableWriting() { events_ &= ~kWriteEvent; update(); }void disableAll() { events_ = kNoneEvent; }int index() { return index_; }void set_index(int idx) { index_ = idx; }// oneloop per thread// 当前Channel所属的eventloopEventLoop* ownerLoop() {return loop_;}void remove();private:void update();void handleEventWithGuard(Timestamp recvTime);static const int kNoneEvent; // 感兴趣的事件类型,该变量表示不感兴趣任何事件static const int kReadEvent; static const int kWriteEvent; EventLoop *loop_; // 事件循环const int fd_;  //fd, poller监听的对象int events_;    // 注册感兴趣的事件int revents_;   // poller返回的具体发生的事件类型(可读?可写?)int index_;std::weak_ptr<void> tie_; // 用于观察shared_ptr的状态bool tied_;// 因为Channel里能得知fd最终发生的具体事件revents_// 故它负责调用对应的回调ReadEventCallback readCallback_;EventCallback writeCallback_;EventCallback closeCallback_;EventCallback errorCallback_;};
// Channel.cpp
#include "Channel.h"
//#include "EventLoop.h"
#include "Logger.h"#include <sys/epoll.h>const int Channel::kNoneEvent = 0; 
const int Channel::kReadEvent = EPOLLIN | EPOLLPRI; 
const int Channel::kWriteEvent = EPOLLOUT;Channel::Channel(EventLoop *loop, int fd): loop_(loop), fd_(fd), events_(0), revents_(0), index_(-1), tied_(false)
{
}Channel::~Channel()
{    
}// ??channel的tie方法什么时候调用过
void Channel::tie(const std::shared_ptr<void> &obj)
{tie_ = obj;tied_ = true;
}// 当改变Channel所表示fd的events事件后,update负责在poller里更改fd相应事件--epoll_ctl
// EventLoop has ChannelList Poller
void Channel::update()
{// 通过Channel所属的EventLoop,调用Poller的相应方法,注册fd的events事件// [TODO]// loop_->updateChannel(this);
}// 在Channel所属的EventLoop中,把当前Channel删除
void Channel::remove()
{// [TODO]// loop_->removeChannel(this);
}// fd得到poller通知后处理事件
void Channel::handleEvent(Timestamp receiveTime)
{if(tied_) // 资源存活{std::shared_ptr<void> guard = tie_.lock();if(guard){handleEventWithGuard(receiveTime);}}else {handleEventWithGuard(receiveTime);}
}// 根据Poller通知的Channel发生的具体事件,调用相应的回调
void Channel::handleEventWithGuard(Timestamp receiveTime)
{LOG_INFO("channel handleEvent revents:%d\n", revents_);// EPOLLHUP 表示读写都关闭if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)){if(closeCallback_){closeCallback_();}}if(revents_ & EPOLLERR){if(errorCallback_){errorCallback_();}}if(revents_ & (EPOLLIN | EPOLLPRI)){if(readCallback_){readCallback_(receiveTime);}}if(revents_ & EPOLLOUT){if(writeCallback_){writeCallback_();}}}

参考资料

  1. 陈硕. 《LInux多线程服务端编程》

  2. 施磊. 《手写C++Muduo网络库》

相关文章:

Muduo库源码剖析(一)——Channel

Muduo库源码剖析(一)——Channel 说明 本源码剖析是在muduo基础上&#xff0c;保留关键部分进行改写分析。 要点总结 事件分发器 event dispatcher中最重要的两个类型 channel 和 Poller Channel可理解为通道&#xff0c;poller往通道传输数据(事件发生情况)。 EventLoop…...

Java多线程:定时器Timer

前言 定时/计划功能在Java应用的各个领域都使用得非常多&#xff0c;比方说Web层面&#xff0c;可能一个项目要定时采集话单、定时更新某些缓存、定时清理一批不活跃用户等等。定时计划任务功能在Java中主要使用的就是Timer对象&#xff0c;它在内部使用多线程方式进行处理&am…...

设计模式---装饰模式

目录 介绍 实现 优缺点 装饰模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。这种类型的设计模式属于结构型模式&#xff0c;它是作为现有类的一个包装。这种模式创建了一个装饰类&#xff0c;用来包装原有…...

跨时钟域传输数据——单bit和多bit信号(总结)

文章目录前言一、慢时钟域到快时钟域1、单bit信号2、多bit信号二、快时钟域到慢时钟域1、单bit信号2、多bit信号三、多bit信号跨时钟域传输1、多个信号合并2、多周期路径 Multi-cycle Path/MCP3、使用格雷码4、使用异步FIFO5、使用DMUX电路结构6、握手信号传输四、简答题1、跨时…...

高并发下如何保证接口幂等

文章目录 1. insert前先select2. 加悲观锁3. 加乐观锁4. 加唯一索引5. 建防重表6. 根据状态机7. 加分布式锁8. 获取token接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题。本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要…...

Retrofit源码分析小结

Retrofit源码分析&小结 简介 Retrofit是对Okhttp网络请求的二次封装&#xff0c;通过注解动态代理的方式&#xff0c;简化了Okhttp的使用&#xff0c;使得通过简单的配置就可以像调用接口一样去请求网络接口&#xff1b;除此之外Retrofit还支持RxJava和kotlin的协程 基本…...

【从零开始学习 UVM】11.4、UVM Register Layer —— UVM Register Model 实战项目(RAL实战,交通灯为例)

文章目录 DesignInterfaceRegister Model ExampleRegister EnvironmentAPB Agent ExampleTestbench EnvironmentSequencesTest在之前的几篇文章中,我们已经了解了寄存器模型是什么以及如何使用它来访问给定设计中的寄存器。现在让我们看一个完整的例子,展示如何为给定设计编写…...

session和token的登录机制

做登录的时候遇到了token &#xff0c;web和smtp的登录情况&#xff0c;这里 记录一下我所学习的两种登录方式&#xff0c;一种是token &#xff0c;一种是session session 登录机制 当用户请求登录接口进行登录服务端 获得登录的信息&#xff0c;从而在数据库中查到相应的用…...

大厂研发成本大曝光,研发占大头

近日&#xff0c;腾讯发布《2022 年腾讯研发大数据报告》&#xff0c;披露了 2022 年腾讯在研发投入、研发效能、开源协同等方面的重要数据。 《报告》显示&#xff0c;2022 年腾讯内部研发人员占比达到 74%&#xff0c;这意味着&#xff0c;平均每四个腾讯员工中&#xff0c;…...

python爬虫第一节基础概念

爬虫是一种自动化抓取互联网上数据的技术。在网络信息爆炸的今天&#xff0c;爬虫技术已经成为数据获取和信息分析的重要手段。本文将详细介绍爬虫的基础知识和操作&#xff0c;帮助初学者快速入门。 一、爬虫的基本原理 爬虫的基本原理是通过网络请求获取网页源代码&#xf…...

web学习---Vue---笔记(1)

该笔记是记录尚硅谷的Vue学习视频的笔记&#xff0c;视频地址为&#xff1a;学习视频地址 初始Vue Vue组件化的特点 组件化声明式编码虚拟DOMDiff算法&#xff0c;尽量复用DOM节点 H5的组件&#xff0c;是把某一个模块封装&#xff0c;里面写HTML\CSS\JS等&#xff0c;算是一…...

【前端面试题——微信小程序】

目录1.请谈谈wxml与标准的html的异同&#xff1f;2.请谈谈WXSS和CSS的异同&#xff1f;3.请谈谈微信小程序主要目录和文件的作用&#xff1f;4.请谈谈小程序的双向绑定和vue的异同&#xff1f;5.简单描述下微信小程序的相关文件类型&#xff1f;6.微信小程序有哪些传值(传递数据…...

gpt模型训练-gpt3模型详解

训练一个GPT模型需要大量的数据集和计算资源。在这里&#xff0c;我提供一些较为通用的训练步骤以供参考&#xff1a; 获取数据集 首先需要收集一些数据集&#xff0c;数据集建议获取大型的常用文本数据集。常见的例如维基百科、各种在线文章、小说、论文等&#xff0c;数据集…...

vue尚品汇商城项目-day04【27.分页器静态组件(难点)】

文章目录27.分页器静态组件&#xff08;难点&#xff09;本人其他相关文章链接27.分页器静态组件&#xff08;难点&#xff09; 难点&#xff1a; 考虑点1&#xff1a;为啥需要分页呢&#xff1f; 答案&#xff1a;按需加载 考虑点2&#xff1a;分页器展示&#xff0c;需要哪…...

使用SeaFile搭建私有云盘并公网访问【cpolar内网穿透】

文章目录1. 前言2. SeaFile云盘设置2.1 Owncould的安装环境设置2.2 SeaFile下载安装2.3 SeaFile的配置3. cpolar内网穿透3.1 Cpolar下载安装3.2 Cpolar的注册3.3 Cpolar云端设置3.4 Cpolar本地设置4. 公网访问测试5. 结语1. 前言 现在我们身边的只能设备越来越多&#xff0c;各…...

蓝桥杯第26天(Python)考前挣扎

题型&#xff1a; 1.思维题/杂题&#xff1a;数学公式&#xff0c;分析题意&#xff0c;找规律 2.BFS/DFS&#xff1a;广搜&#xff08;递归实现&#xff09;&#xff0c;深搜&#xff08;deque实现&#xff09; 3.简单数论&#xff1a;模&#xff0c;素数&#xff08;只需要…...

WuThreat身份安全云-TVD每日漏洞情报-2023-04-04

漏洞名称:RSA NetWitness Platform 内存损坏漏洞 漏洞级别:中危 漏洞编号:CVE-2022-47529,CNNVD-202303-2419 相关涉及:RSA NetWitness Platform 12.2之前版本 漏洞状态:POC 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-07193 漏洞名称:EyouCms <1.5.…...

【C++】Step by Step的格式化代码风格是这样的吗?

文章目录前言一、依赖二、配置总结前言 本节从0开始讲解如何格式化自己的代码风格&#xff0c;使用vscode插件来完成&#xff0c;本节的所有配置都会在星球同步哦~ 一、依赖 本次使用的是clang-format插件&#xff0c;具体安装比较简单&#xff1a; mac系统&#xff1a; br…...

aspnet030高校学生团体管理系统sqlserver

net030高校学生团体管理系统 . 1.用户基本信息管理模块&#xff1a;录入、修改、删除、查询、统计、打印等功能 2.学生成绩管理模块&#xff1a;录入、修改、删除、查询、统计、打印等功能 3.学生团体信息管理模块&#xff1a;录入、修改、删除、查询、统计、打印等功能 4.教…...

学习HM微博项目第10天

步骤&#xff1a;发微博12-表情键盘06-点击表情 -> 发微博13-表情键盘07-插入表情和封装textView -> 发微博14-表情键盘08-长按表情 -> 发微博15-表情键盘09-最近表情 -> 发微博16-表情键盘10-最近表情完善 发微博12-表情键盘06-点击表情 APP的演示动画&#xff…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

土建施工员考试:建筑施工技术重点知识有哪些?

《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目&#xff0c;核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容&#xff0c;附学习方向和应试技巧&#xff1a; 一、施工组织与进度管理 核心目标&#xff1a; 规…...

Mysql故障排插与环境优化

前置知识点 最上层是一些客户端和连接服务&#xff0c;包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念&#xff0c;为通过安全认证接入的客户端提供线程。同样在该层上可…...