muduo库中的Channel类封装了需要监听的fd以及fd感兴趣的事件events和返回的事件revents
TcpServer相当于是muduo库提供给外部编写服务器程序的一个类,相当于一个工具箱,把muduo库有关服务器的编程相关的东西,包括反应堆,事件分发器,事件回调都打包一块了
我们看看它的成员变量 EventLoop就是开启epoll_wait事件循环,可以理解成epoll,我们看看EventLoop具体怎么实现的 EventLoop的成员变量 Poller相当于是epoll抽象的概念,用Poller当做基类,在派生类中实现了poll和epoll,poll和epoll负责事件分发
此外,epoll还需要监听socket。我们注意到,在EventLoop类内除了编译器内置类型,自定义类型只有两个,Poller和Channel
我们看看Channel的一些成员变量 Channel包含了监听的sockfd,感兴趣的事件和发生的事件 Eventloop是事件循环(epoll_wait),相当于事件分发器,包含了Poller(epoll)和Channel(epoll监听的sockfd,以及它对应的事件和最终发生的事件),对应Reactor模型上的多路事件分发器Demultiplex
一个channel属于一个EventLoop,一个EventLoop对应多个channel,一个channel封装了一个fd和这个fd对应的感兴趣的事件以及发生的事件
Channel要向Poller注册感兴趣事件,Poller通知Channel发生的事件,Channel得到关于fd的事件通知会调用预置的回调操作
一个线程对应一个eventloop,一个eventloop有一个poller,一个poller可以监听多个channel,每个channel属于一个eventloop,一个eventloop有很多channel,这就是多路;一个线程监听多路fd
Channel.h
#pragma once
#include "noncopyable.h"
#include "Timestamp.h"
#include <functional>
#include <memory>
class EventLoop;
class Channel : noncopyable{
public:
using EventCallBack = std::function<void()>;
using ReadEventCallBack = std::function<void(Timestamp)>;
Channel(EventLoop* loop, int fd);
~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 errorCloseCallBack(EventCallBack cb){ errorCallBack_ = std::move(cb); }
void tie(const std::shared_ptr<void>&);
int fd() const { return fd_; }
int events() const{ return events_; }
void set_revents(int revt){ revents_ = revt; }
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 isNoneEvent() const{ return events_ == kNoneEvent; }
bool isWritingEvent() const{ return events_ & kWriteEvent; }
bool isReadingEvent() const{ return events_ & kReadEvent; }
int index(){ return index_; }
void set_index(int idx){ index_ = idx; }
EventLoop* ownerLoop(){ return loop_; }
void remove();
private:
void update();
void handleEventWithGaurd(Timestamp receiceTime);
static const int kNoneEvent;
static const int kReadEvent;
static const int kWriteEvent;
EventLoop* loop_;
const int fd_;
int events_;
int revents_;
int index_;
std::weak_ptr<void> tie_;
bool tied_;
ReadEventCallBack readCallback_;
EventCallBack writeCallBack_;
EventCallBack closeCallBack_;
EventCallBack errorCallBack_;
};
Channel类析构函数源码如下:
Channel::~Channel()
{
assert(!eventHandling_);
assert(!addedToLoop_);
if (loop_->isInLoopThread())
{
assert(!loop_->hasChannel(this));
}
}
由于muduo源码中的Channel析构函数没有任何释放资源的操作,我们也就不写了
Channel::~Channel(){}
得到Poller通知后,Channel需要调用,处理事件
handleEvent源码如下:
void Channel::handleEvent(Timestamp receiveTime)
{
std::shared_ptr<void> guard;
if (tied_)
{
guard = tie_.lock();
if (guard)
{
handleEventWithGuard(receiveTime);
}
}
else
{
handleEventWithGuard(receiveTime);
}
}
那tie方法什么时候执行?有什么作用呢?后面再补
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;
}
void Channel::update(){
loop_->updateChannel(this);
}
void Channel::remove(){
loop_->removeChannel(this);
}
void Channel::handleEvent(Timestamp receiveTime){
if(tied_){
std::shared_ptr<void> guard = tie_.lock();
if(guard){
handleEventWithGaurd(receiveTime);
}
}else{
handleEventWithGaurd(receiveTime);
}
}
void Channel::handleEventWithGaurd(Timestamp receiveTime){
LOG_INFO("channel handleEvent revents: %d\n", revents_);
if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)){
if(closeCallBack_){
closeCallBack_();
}
}
if(revents_ & EPOLLERR){
if(errorCallBack_){
errorCallBack_();
}
}
if(revents_ & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)){
if(readCallBack_){
readCallBack_(receiveTime);
}
}
if(revents_ & EPOLLOUT){
if(writeCallBack_){
writeCallBack_();
}
}
}
|