muduo源码剖析之channel通道类

编程入门 行业动态 更新时间:2024-10-28 06:35:17

muduo<a href=https://www.elefans.com/category/jswz/34/1770099.html style=源码剖析之channel通道类"/>

muduo源码剖析之channel通道类

简介

channel是muduo中的事件分发器,它只属于一个EventLoop,Channel类中保存着IO事件的类型以及对应的回调函数,每个channel只负责一个文件描述符,但它并不拥有这个文件描述符。channel是在epoll和TcpConnection之间起沟通作用,故也叫做通道,其它类通过调用channel的setCallbcak来和建立channel沟通关系。

Channel类主要作用:

  1. 将文件描述符(可能是socket类型,eventfd类型,timefd类型,signalfd类型)封装,通过该类设置各种事件的回调函数(例如读回调,写回调,关闭回调等)。
  2. 可以设置自己的监听事件类型,然后根据该类型更新poller对象(epoll或者poll)对该类的操作(例如添加,修改,删除操作)。
  3. 根据自己监听到的事件类型触发回调函数。

源码剖析

channel.h

///
///一个能被选择的 I/O channel
//这个类不拥有自己的文件描述符
/// 这个文件描述符可能是socket,eventfd, timerfd,或者 signalfd.class Channel : noncopyable
{public:typedef std::function<void()> EventCallback;	//事件回调typedef std::function<void(Timestamp)> ReadEventCallback;	//读事件回调Channel(EventLoop* loop, int fd);	//一个channel属于一个loop,一个loop可以对应多个channel~Channel();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与shared_ptr管理的所有者对象绑定,///阻止shared_ptr管理的所有者对象在handleEvent被销毁void tie(const std::shared_ptr<void>&);int fd() const { return fd_; }int events() const { return events_; }	//返回注册的事件void set_revents(int revt) { revents_ = revt; } // 设置监听到的事件类型// int revents() const { return revents_; }bool isNoneEvent() const { return events_ == kNoneEvent; }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(); }	//不监听任何事件bool isWriting() const { return events_ & kWriteEvent; }	//是否监听写事件bool isReading() const { return events_ & kReadEvent; }	//是否监听读事件// for Pollerint index() { return index_; }	//poller事件数组中的下标void set_index(int idx) { index_ = idx; }	// for debugstring reventsToString() const;string eventsToString() const;void doNotLogHup() { logHup_ = false; }EventLoop* ownerLoop() { return loop_; }	//返回所属的loopvoid remove();	//将channel从loop中移除private:static string eventsToString(int fd, int ev);void update();	//根据index_的状态,控制监听数组void handleEventWithGuard(Timestamp receiveTime);	//对监听到事件的一个处理static const int kNoneEvent;  //无事件static const int kReadEvent;  //可读事件static const int kWriteEvent; //可写事件EventLoop* loop_;const int  fd_;int        events_;	//监听的事件类型int        revents_; 	//监听到的事件类型 int        index_; 	// 表示poller事件数组中的序号bool       logHup_;	std::weak_ptr<void> tie_;bool tied_;	bool eventHandling_;	//是否处于处理事件中bool addedToLoop_;	//是否添加到loop上ReadEventCallback readCallback_;	//读回调EventCallback writeCallback_;	//写回调EventCallback closeCallback_;	//关闭回调EventCallback errorCallback_;	//错误回调
};

channel

// Copyright 2010, Shuo Chen.  All rights reserved.
// /
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include "muduo/base/Logging.h"
#include "muduo/net/Channel.h"
#include "muduo/net/EventLoop.h"#include <sstream>#include <poll.h>using namespace muduo;
using namespace muduo::net;const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;//Channel(事件分发器),只属于一个EventLoop,Channel类中保存着IO事件的类型以及对应的回调函数,每个channel只负责一个文件描述符
Channel::Channel(EventLoop* loop, int fd__): loop_(loop),        //channel所属的loop,一个channel只属于一个loopfd_(fd__),          //channel负责的文件描述符events_(0),         //注册的事件revents_(0),        //poller设置的就绪的事件index_(-1),         //被poller使用的下标logHup_(true),      //是否生成某些日志tied_(false),   用于tie()方法eventHandling_(false),          //处理handevent的标志addedToLoop_(false)		//是否正在循环监听中
{
}Channel::~Channel()
{assert(!eventHandling_);assert(!addedToLoop_);if (loop_->isInLoopThread())//one loop per thread,判断event_loop所在的线程和正在销毁该对象的线程是不是同一个线程{assert(!loop_->hasChannel(this));//该对象此时不属于loop_并且poller中也没有该记录才能销毁成功}
}void Channel::tie(const std::shared_ptr<void>& obj)
{tie_ = obj;tied_ = true;
}void Channel::update()   //根据index_的状态,控制该channel的监听状态
{addedToLoop_ = true;loop_->updateChannel(this);//该函数最底层实际是由Poller->updateChannel(this)实现的
}void Channel::remove()  //同上
{assert(isNoneEvent());addedToLoop_ = false;loop_->removeChannel(this);//将该对象从Poller监听的数组对象中移除出去
}//处理所有发生的事件,如果活着,底层调用handleEventWithGuard
void Channel::handleEvent(Timestamp receiveTime) //事件到来调用handleEvent处理
{std::shared_ptr<void> guard;       //守护if (tied_){guard = tie_.lock();if (guard){handleEventWithGuard(receiveTime);//实际上处理的函数}}else{handleEventWithGuard(receiveTime);}
}//处理所有发生的事件
//EPOLLIN :表示对应的文件描述符可以读; 
//EPOLLOUT:表示对应的文件描述符可以写; 
//EPOLLPRI:表示对应的文件描述符有紧急的数据可读 
//EPOLLERR:表示对应的文件描述符发生错误; 
//EPOLLHUP:表示对应的文件描述符被挂断; 
//EPOLLET:表示对应的文件描述符有事件发生; 
void Channel::handleEventWithGuard(Timestamp receiveTime)
{					eventHandling_ = true;			LOG_TRACE << reventsToString();if ((revents_ & POLLHUP) && !(revents_ & POLLIN))  //判断返回事件类型{if (logHup_){LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";}if (closeCallback_) closeCallback_();}if (revents_ & POLLNVAL)                 //不合法文件描述符{LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";}if (revents_ & (POLLERR | POLLNVAL)){if (errorCallback_) errorCallback_();}if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))   //POLLRDHUP是对端关闭连接事件,如shutdown等{if (readCallback_) readCallback_(receiveTime);}if (revents_ & POLLOUT){if (writeCallback_) writeCallback_();}//事件处理完成,将事件处理标志职位falseeventHandling_ = false;
}//将revents转为string,方便输出调试
string Channel::reventsToString() const
{return eventsToString(fd_, revents_);
}//将events转为string,方便输出调试
string Channel::eventsToString() const
{return eventsToString(fd_, events_);
}//实际上events和revents转为string类型的实现
string Channel::eventsToString(int fd, int ev)
{std::ostringstream oss;oss << fd << ": ";if (ev & POLLIN)oss << "IN ";if (ev & POLLPRI)oss << "PRI ";if (ev & POLLOUT)oss << "OUT ";if (ev & POLLHUP)oss << "HUP ";if (ev & POLLRDHUP)oss << "RDHUP ";if (ev & POLLERR)oss << "ERR ";if (ev & POLLNVAL)oss << "NVAL ";return oss.str();
}

更多推荐

muduo源码剖析之channel通道类

本文发布于:2023-12-05 15:29:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1664569.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:源码   通道   muduo   channel

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!