muduo源码剖析--Channel类

Channel类剖析

channel在muduo中是对文件描述符的一种底层封装,具体而言是封装了对某个文件描述符的读写事件、错误事件、关闭事件的回调,并主要与EventLoop类进行交互,而EventLoop实际上是根据channel的调用实际调用poller或者EpollPoller进行文件描述符具体事件的管理。

public:
    using EventCallback = std::function<void()>; // muduo仍使用typedef
    using ReadEventCallback = std::function<void(Timestamp)>;
    
    int fd() const { return fd_; }
    int events() const { return events_; }
    
private:

    void update();
    void handleEventWithGuard(Timestamp receiveTime);
//封装具体的事件
    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最终发生的具体的事件events,所以它负责调用具体事件的回调操作
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;

poller设置相应的活跃事件,通过调用通道的set_revents方法

void set_revents(int revt) { revents_ = revt; }

设置回调函数对象,主要注册具体的回调函数,Channel具体不会关系回调是怎么实现的,只负责具体的调用

	//设置读回调
	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); }

设置fd相应的事件状态 实际上是在EventLoop对象中调用了epoll_ctl add delete这些底层的函数对管理fd在epoll上所关心的事件信息。
需要说明的是,一个EventLoop对象相当于一个事件循环,也即Reactor模式,Reactor中是会有多个fd的,而一个fd对应一个Channel,那么一个EventLoop对象里面包含了多个Channel对象,也即一对多的关系,但是一个Channel对象只能隶属于一个EventLoop对象。


	const int Channel::kNoneEvent = 0; //空事件
	const int Channel::kReadEvent = EPOLLIN | EPOLLPRI;  //读事件
	const int Channel::kWriteEvent = EPOLLOUT; //写事件

	void enableReading() { events_ |= kReadEvent; update(); }
    void disableReading() { events_ &= ~kReadEvent; update(); }
    void enableWriting() { events_ |= kWriteEvent; update(); }
    void disableWriting() { events_ &= ~kWriteEvent; 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; }

	void Channel::update()
	{
	    // 通过channel所属的eventloop,调用poller的相应方法,注册fd的events事件
	    loop_->updateChannel(this);
	}

loop监听到某个channel所关心的事件之后,会让自己所管理channel调用相应的读写关闭错误事件回调,即:handleEvent->handleEventWithGuard。

// fd得到Poller通知以后 处理事件 handleEvent在EventLoop::loop()中调用
  public:
    void handleEvent(Timestamp receiveTime);
private:
    void handleEventWithGuard(Timestamp receiveTime);

void Channel::handleEvent(Timestamp receiveTime)
{
    if (tied_)
    {
        std::shared_ptr<void> guard = tie_.lock();
        if (guard)
        {
            handleEventWithGuard(receiveTime);
        }
        // 如果提升失败了 就不做任何处理 说明Channel的TcpConnection对象已经不存在了
    }
    else
    {
        handleEventWithGuard(receiveTime);
    }
}

void Channel::handleEventWithGuard(Timestamp receiveTime)
{
    LOG_INFO("channel handleEvent revents:%d\n", revents_);
    // 关闭
    if ((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) // 当TcpConnection对应Channel 通过shutdown 关闭写端 epoll触发EPOLLHUP
    {
        if (closeCallback_)
        {
            closeCallback_();
        }
    }
    // 错误
    if (revents_ & EPOLLERR)
    {
        if (errorCallback_)
        {
            errorCallback_();
        }
    }
    // 读
    if (revents_ & (EPOLLIN | EPOLLPRI))
    {
        if (readCallback_)
        {
            readCallback_(receiveTime);
        }
    }
    // 写
    if (revents_ & EPOLLOUT)
    {
        if (writeCallback_)
        {
            writeCallback_();
        }
    }
}

channel生命周期的问题:

// 防止当channel被手动remove掉 channel还在执行回调操作
    void tie(const std::shared_ptr<void> &);
private:
	std::weak_ptr<void> tie_;
    bool tied_;

// channel的tie方法什么时候调用过?  TcpConnection => channel
/**
 * TcpConnection中注册了Chnanel对应的回调函数,传入的回调函数均为TcpConnection
 * 对象的成员方法,因此可以说明一点就是:Channel的结束一定早于TcpConnection对象!
 * 此处用tie去解决TcoConnection和Channel的生命周期时长问题,从而保证了Channel对
 * 象能够在TcpConnection销毁前销毁。
 **/
void Channel::tie(const std::shared_ptr<void> &obj)
{
    tie_ = obj;
    tied_ = true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值