Reactor模型图
目前 TcpServer 类需要封装的两个类, 一个是事件循环类 ,一个是IP地址端口打包类,IP地址打包的类封装完。
而EventLoop 下还需要两个重要类:一个是channel通道类,一个是poller抽象类
现在我们需要的补上TcpServer类 EventLoop类
TcpServer.h
对外使用编程服务器的类
- #pragma once
-
-
- class TcpServer
- {
- public:
- private:
- };
EventLoop.h
事件循环类 主要包含了两大模块, channel poller(epoll的抽象,muduo库中也实现了poll)
- #pragma once
-
- class EventLoop
- {
- public:
- private:
- };
Channel.h
EventLoop、Channel、Poller之间的关系 是EventLoop 包含了它两, Readctor模型上的Demultipex
channel 理解为通道,封装了sockfd和其感兴趣的event, 如EPOLLIN、EPOLLOUT事件。 还绑定了poller返回的事件
Channel的成员变量:
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
bool tied_;
ReadEventCallback readCallback_; 用户注册的读回调
EventCallback writeCallback_; 用户注册的写回调
EventCallback closeCallback_; 用户注册的关闭回调
EventCallback errorCallback_; 用户注册的错误回调
- #pragma once
- #include
- #include
- #include "noncopyable.h"
- #include "Timestamp.h"
- //头文件里边只用了类型的声明,没有用到类型具体的定义以及方法,所以我们在这头文件中就只需要一些前置声明一下就好
- class EventLoop;
-
-
-
- class Channel:public noncopyable
- {
- public:
- //绑定回调函数
- using EventCallback = std::function<void()>;
- using ReadEventCallback = std::function<void(Timestamp)>;
-
- //因为是指针都是4字节,不影响编译,所以前置声明就好了
- Channel(EventLoop *loop, int fd);
- ~Channel();
- //这个Timestamp需要计算类大小,所以不能只做前置声明
- //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_; }
-
- //设置fd事件,因为是poller监听的,所以需要对外提供一个接口去设置
- int set_revents(int rev) { events_ = rev ; }
-
- //设置fd相应的时间状态,也就是给epoll_ctl 设置
- 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 isWriting() const { return events_ & kWriteEvent; }
- bool isReading() const { return events_ & kReadEvent; }
-
- int index() { return index_; }
- void set_index(int idx) { index_ = idx; }
-
- //当前channel属于哪个eventLoop,一个EventLoop有很多个channel,一个线程一个EventLoop
- EventLoop* ownerLoop() { return loop_; }
- void remove();
-
- private:
- void update();
- void handleEventWithhGuard(Timestamp receiveTime);
-
- private:
-
- //表示FD的一个状态
- 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_;
-
- //channel能获知fd最终发生的具体事件revents,所以它负责调用具体事件的回调操作
- ReadEventCallback readCallback_;
- EventCallback writeCallback_;
- EventCallback closeCallback_;
- EventCallback errorCallback_;
- };
Channel.cc
- #include "Channel.h"
- #include "EventLoop.h"
- #include "Logger.h"
-
- #include
-
- 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(){}
-
- //channel里的tie方法什么时候被调用过? 后边再看
- void Channel::tie(const std::shared_ptr<void> &obj)
- {
- tie_ = obj; //绑定成弱智能指针观察强智能指针
- tied_ = true;//绑定过了就置成true
- }
-
- /**
- * @brief 当改变channel所表示fd的events事件后,update负责在poller里面更改fd相应的时间epoll_ctl
- *
- * poller在哪呢? poller 跟channel是两个不同的模块。因为epoll不属于channel管,但是他们两都是数据EventLoop的
- *
- * EventLoop 包含了ChannelList"也就是一个channel列表", 和一个poller
- *
- * 所以channel本身想向Channel注册fd对应的事件是做不了的,因为它又没有poller对象,所以需要通过EventLoop来做这件事情
- *
- */
- void Channel::update()
- {
- //通过Channel所属的EventLoop,调用poller的相应方法,注册fd的Events事件
- //add code
- //loop_->updateChannel(this);
- }
-
- //在channel所属的EventLoop中的容器,把自己给删除掉
- void Channel::remove()
- {
- //add code
- // loop_->removeChannel(this);
- }
-
-
- //fd得到poller通知以后,处理事件的
- void Channel::handleEvent(Timestamp receiveTime)
- {
- if(tied_)
- {
- std::shared_ptr<void> guard = tie_.lock();
- if(guard)
- {
- handleEventWithhGuard(receiveTime);
- }
- }
- else
- {
- handleEventWithhGuard(receiveTime);
- }
- }
-
- //根据poller通知的channel发生的具体事件,由channel负责调用具体的回调操作
- void Channel::handleEventWithhGuard(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_();
- }
- }
-
- }
channel.cc 中还有三个遗留问题:
void Channel::remove():下次补全方法
看看后边tie方法什么时候被调用过? 因为它触发了之后才会触发void Channel::handleEvent里边的弱智能指针的提升