2023-11-07 muduo库学习之仿写代码4 Channel类及实现

Channel介绍

Channel 理解为通道,封装了sockfd和其感兴趣的event,如EPOLLIN、EPOLLOUT事件还绑定了poller返回的具体事件

EventLoop内包含poller和channel, channel中包含了fd和感兴趣的事件以及真实发生的事件,这些事件要向poller中注册,发生的事件由poller向channel通知,channel得到相应fd的事件通知后,调用相应的回调操作

Channel.h

#pragma once

#include "noncopyable.h"
#include "Timestamp.h"

#include <functional>
#include <memory>

// 类的前置声明
class EventLoop;

/*
Channel 理解为通道,封装了sockfd和其感兴趣的event,如EPOLLIN、EPOLLOUT事件
还绑定了poller返回的具体事件

EventLoop内包含poller和channel,
channel中包含了fd和感兴趣的事件以及真实发生的事件,
这些事件要向poller中注册,发生的事件由poller向channel通知,
channel得到相应fd的事件通知后,调用相应的回调操作
*/

class Channel : noncopyable{
public:
    //typedef std::function<void()> EventCallback;
    //C++ 11语法 using
    using EventCallback = std::function<void()>;
    using ReadEventCallback = std::function<void(Timestamp)>;

    Channel(EventLoop* loop, int fd);
    ~Channel();

    // fd得到poller通知以后,处理事件(调用相应的回调方法)
    void handleEvent(Timestamp receiveTime);

    // 设置回调函数对象
    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相应的事件状态
    void enableReading() {events_ |= kReadEvent; update();}
    void disableReading() {events_ &= ~kReadEvent; update();}
    void enableWriting() {events_ |= kWriteEvent; update();}
    void disableWriting() {events_ &= ~kReadEvent; update();}
    void disableAll() {events_ = kNoneEvent; update();}

    // 返回fd当前的事件状态
    bool isNoneEvent() const {return events_ == kNoneEvent;}
    bool isWriting() const {return events_ & kWriteEvent;}
    bool isReading() const {return events_ & kReadEvent;}

    int index() {return index_;}
    void set_index(int idx) {index_ = idx;}

    // one loop per thread
    EventLoop* ownerLoop() {return loop_;}
    void remove();

private:

    static const int kNoneEvent; //没有事件
    static const int kReadEvent; // 读事件
    static const int kWriteEvent; // 写事件

    EventLoop *loop_; // 事件循环
    const int fd_;// fd, Poller监听的对象
    int events_;// 注册fd感兴趣的事件
    int revents_;// poller返回的具体发生的事件
    int index_;

    std::weak_ptr<void> tie_; 
    bool tied_;

    // 因为Channel通道里能够获知fd最终发生的具体的事件revents,所以它负责调用具体事件的回调操作
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;

    void update();
    void handleEventWithGuard(Timestamp receiveTime);

};

Channel.cc

#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(){

}

void Channel::tie(const std::shared_ptr<void> &obj) {
    tie_ = obj;
    tied_ = true;
}

/*
当改变channel所表示的fd的events事件后,update负责在poller里面更改fd相应的事件epoll_ctl
*/
void Channel::update(){
    //通过channel所属的EventLoop,调用poller的相应方法,注册fd的events事件
    // add code...
    // loop_ ->updateChannel(this);
}

// 在channel所属的EventLoop中,把当前的channel删除掉
void Channel::remove(){
    //add code..
    //loop_->removeChannel(this);
}

void Channel::handleEvent(Timestamp receiveTime) {
    if (tied_) {
        std::shared_ptr<void> guard = tie_.lock();
        if(guard) {
            handleEventWithGuard(receiveTime);
        }
    }else {
        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) {
        if(errorCallback_) {
            errorCallback_();
        }
    }

    if(revents_ & (EPOLLIN | EPOLLPRI)) {
        if(readCallback_) {
            readCallback_(receiveTime);
        }
    }

}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容