基于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_();
        }
    }
}
相关文章
|
2月前
|
网络协议 算法 Java
基于Reactor模型的高性能网络库之Tcpserver组件-上层调度器
TcpServer 是一个用于管理 TCP 连接的类,包含成员变量如事件循环(EventLoop)、连接池(ConnectionMap)和回调函数等。其主要功能包括监听新连接、设置线程池、启动服务器及处理连接事件。通过 Acceptor 接收新连接,并使用轮询算法将连接分配给子事件循环(subloop)进行读写操作。调用链从 start() 开始,经由线程池启动和 Acceptor 监听,最终由 TcpConnection 管理具体连接的事件处理。
60 2
|
2月前
基于Reactor模型的高性能网络库之Tcpconnection组件
TcpConnection 由 subLoop 管理 connfd,负责处理具体连接。它封装了连接套接字,通过 Channel 监听可读、可写、关闭、错误等
76 1
|
2月前
基于Reactor模式的高性能网络库github地址
https://github.com/zyi30/reactor-net.git
48 0
|
9月前
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
219 17
|
9月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
171 10
|
9月前
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
9月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
175 10
|
9月前
|
监控 安全 网络安全
网络安全与信息安全:漏洞、加密与意识的交织
在数字时代的浪潮中,网络安全与信息安全成为维护数据完整性、保密性和可用性的关键。本文深入探讨了网络安全中的漏洞概念、加密技术的应用以及提升安全意识的重要性。通过实际案例分析,揭示了网络攻击的常见模式和防御策略,强调了教育和技术并重的安全理念。旨在为读者提供一套全面的网络安全知识框架,从而在日益复杂的网络环境中保护个人和组织的资产安全。
|
9月前
|
存储 监控 安全
云计算与网络安全:云服务、网络安全、信息安全等技术领域的融合与挑战
本文将探讨云计算与网络安全之间的关系,以及它们在云服务、网络安全和信息安全等技术领域中的融合与挑战。我们将分析云计算的优势和风险,以及如何通过网络安全措施来保护数据和应用程序。我们还将讨论如何确保云服务的可用性和可靠性,以及如何处理网络攻击和数据泄露等问题。最后,我们将提供一些关于如何在云计算环境中实现网络安全的建议和最佳实践。
|
9月前
|
安全 算法 网络协议
网络安全与信息安全知识分享
本文深入探讨了网络安全漏洞、加密技术以及安全意识三个方面,旨在帮助读者更好地理解和应对网络安全威胁。通过分析常见的网络安全漏洞类型及其防范措施,详细介绍对称加密和非对称加密的原理和应用,并强调提高个人和企业安全意识的重要性,为构建更安全的网络环境提供指导。
168 2

热门文章

最新文章