TcpServer相当于是muduo库提供给外部编写服务器程序的入口的一个类,相当于一个大箱子,把muduo库有关服务器的编程相关的东西,包括反应堆,事件分发器,事件回调都打包一块了。
我们看看它的成员变量。
事件分发器相当于epoll,在多核的CPU时代,不可能只是一个线程,所以肯定有一个事件分发的线程池EventLoopThreadPool;ConnectionMap维护了所有连接。
我们先从EventLoop往下看
eventloop事件循环相当于是一个epoll,epoll里面主要管理什么呢?查看它的成员变量
poller相当于epoll的抽象概念,用poller当做一个基类,在派生类里面实现了poll和epoll这些io复用的具体的事件分发操作。epoll里面还得需要监听socket,eventloop里另外一个重要的成员变量channel
事件分发器在这里面最重要的两个东西:poller和channel
我们看一下channel是什么
revents是具体的发生的事件
channel我们理解成通道,相当于就是fd和它所绑定的感兴趣的事件和实际上发生事件epoll_wait返回以后在fd上发生的事件(绑定)。
eventloop包含channel eventloop是事件循环,相当于事件分发器一样,包含了epoll,也就是poller,另外就是epoll感兴趣的fd,以及它对应的事件和最终发生的事件被muduo库封装成channel 这些事件最终要向poller注册,发生的事件由poller给channel通知,channel得到相应fd的事件通知调用预置的回调操作。 一个线程有一个eventloop,一个eventloop有一个poller,一个poller可以监听多个channel,每个channel属于1个eventloop,1个eventloop有很多channel,这就是多路。
重写Channel
Channel.h
#pragma once
#include "noncopyable.h"
#include "Timestamp.h"
#include<functional>
#include<memory>
class EventLoop;
/*
理清楚EventLoop、channel和Poller之间的关系,他们在reactor模型上对应Demultiplex多路事件分发器
channel理解为通道,封装了sockfd和其感兴趣的event,如EPOLLIN、EPOLLOUT事件
还绑定了poller返回的具体事件
*/
class Channel : noncopyable
{
public:
using EventCallback = std::function<void()>; //事件回调
using ReadEventCallback = std::function<void(Timestamp)>; //只读事件回调
Channel(EventLoop *loop,int fd);
~Channel();
//fd得到poller通知以后,处理事件的
//调用相应的回调方法来处理事件
/*构造函数中的EventLoop只是前置声明就可以了,因为这里只用了类型定义的指针,不管是什么类型指针都是四个字节,不影响编译;
但是TimeStamp这里是定义的变量,需要确定变量的大小,所以需要包含它的头文件
*/
//fd得到poller通知以后,调用相应的回调方法处理事件
void handleEvent(Timestamp receiveTime);
//设置回调函数对象
//因为cb和这个成员变量都属于左值,有内存和变量名字,因为function是一个对象,对象我们假设它是很大的,占用很多资源,在这里面调用的就是函数对象的赋值操作,
//所以要把cb转成一个右值,把cb的资源转给成员变量,因为出了这个函数,cb形参的局部对象就不需要了,
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_; } //fd所感兴趣的事件
void set_events(int revt) { revents_ = revt; } //poller监听事件,设置了channel的fd相应事件
//设置fd相应的事件状态,要让fd对这个事件感兴趣
//update就是调用epoll_ctrl,通知poller把fd感兴趣的事件添加到fd上
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; }
int index() { return index_; }
void set_index(int idx) { index_ = idx; }
//one loop per thread
EventLoop* ownerLoop() { return loop_; }//当前channel属于哪个eventloop
void remove();//删除channel
private:
void update();//更新,内部对象调用
void handleEventWithGuard(Timestamp receiveTime);//受保护的处理事件
//表示当前fd和其状态,是没有对任何事件感兴趣,还是对读或者写感兴趣
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_;
/*
防止手动调用removeChannel,Channel被手动remove以后我们还在使用Channel,
所以做了跨线程的对象的生存状态的监听,使用的时候可以把弱智能指针提升成强智能指针,
提升成功访问,提升失败说明已经被释放。
*/
std::weak_ptr<void> tie_; //绑定自己
bool tied_;
//因为channel通道里面能够获知fd最终发生的具体的事件revents,所以它负责调用具体事件的回调操作
//这些回调是用户设定的,通过接口传给channel来负责调用 ,channel才知道fd上是什么事件
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
};
析构函数的if:如果这个channel是在当前的事件循环所在的线程里面
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; //epoll的表示
const int Channel::kWriteEvent = EPOLLOUT; //epoll的表示
//EventLoop底层: ChannelList Poller 每个channel属于1个loop
Channel::Channel(EventLoop *loop,int fd)
:loop_(loop), fd_(fd), events_(0), revents_(0), index_(-1), tied_(false)
{}
//析构函数
//保证没有正在处理的回调操作
//保证channel要么是从来没使用过,要么是被remove掉后才能析构
//判断当前的loop是否在它所在的线程去析构的channel
Channel::~Channel()
{}
//channel的tie方法什么时候调用过?一个TcpConnection新连接创建的时候 TcpConnection => Channel
void Channel::tie(const std::shared_ptr<void> &obj){
tie_ = obj;
tied_ = true;
}
/*
当改变channel所表示fd的events事件后,update负责在poller里面更改fd相应的事件epoll_ctl
EventLoop => ChannelList Poller
*/
void Channel::update(){
//通过channel所属的EventLoop,调用poller的相应方法,注册fd的events事件
loop_->updateChannel(this);
}
//在channel所属的EventLoop中, 把当前的channel删除掉
void Channel::remove(){
loop_->removeChannel(this);
}
//fd得到poller通知以后,调用相应的回调方法处理事件
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 revent:%d\n",revents_);
if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)){
if(closeCallback_){
closeCallback_();
}
}
if(revents_ & EPOLLERR){
if(errorCallback_){
errorCallback_();
}
}
if(revents_ & (EPOLLIN|EPOLLPRI)){
if(readCallback_){
readCallback_(receiveTime);
}
}
if(revents_ & EPOLLOUT){
if(writeCallback_){
writeCallback_();
}
}
}