文章中不免有错误之处,如若发现,恳请指正,感恩不尽!
muduo库事件循环机制总体实现逻辑理解
主从Reactor之间交互
- 主Reactor主要负责接收新连接请求,然后将该连接发送给从Reactor进行处理
- 从Reactor则是监听主Reactor交付给它的请求,然后对其进行处理
单个Reactor执行逻辑
- EventLoop不断调用poll来监听多个文件描述符的事件
- 当poll检测到某个文件描述符上事件发生的时候,会通知EventLoop
- EventLoop根据事件找到对应的Channel,然后通过Channel预先注册好的回调函数,来处理对应的事件
新连接与Channel的关系
总体架构
代码分析范围
各模块的主要功能
EventLoop
管理事件循环,调度各类事件的处理。Poller
监听并管理所有的I/O事件。Channel
将具体的文件描述符与事件处理函数关联起来。
各模块逻辑分析
EventLoop模块
事件循环的核心模块,主要负责事件的启动和维护事件循环的运行,处理不同的事件,该模块管理着poller和Channel模块。
核心成员函数和变量
class EventLoop : noncopyable
{
public:
typedef std::function<void()> Functor;
EventLoop();
~EventLoop();
void loop();
void quit();
void runInLoop(Functor cb);
void queueInLoop(Functor cb);
void wakeup();
void updateChannel(Channel* channel);
void removeChannel(Channel* channel);
bool hasChannel(Channel* channel);
private:
void abortNotInLoopThread();
void handleRead();
void doPendingFunctors();
typedef std::vector<Channel*> ChannelList;
bool looping_;
std::atomic<bool> quit_;
bool eventHandling_;
bool callingPendingFunctors_;
int64_t iteration_;
const pid_t threadId_;
Timestamp pollReturnTime_;
std::unique_ptr<Poller> poller_;
std::unique_ptr<TimerQueue> timerQueue_;
int wakeupFd_;
std::unique_ptr<Channel> wakeupChannel_;
ChannelList activeChannels_;
Channel* currentActiveChannel_;
mutable MutexLock mutex_;
std::vector<Functor> pendingFunctors_;
};
核心模块:loop方法,通过调用poller和poll方法来获取当前已经就绪的新连接文件描述符,然后调用事先已经设置好的回调函数,执行其逻辑
void EventLoop::loop()
{
assert(!looping_);
looping_ = true;
quit_ = false;
while (!quit_) {
activeChannels_.clear();
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
for (Channel* channel : activeChannels_) {
channel->handleEvent(pollReturnTime_);
}
doPendingFunctors();
}
looping_ = false;
}
poller模块
对多路复用机制的封装
核心成员函数和变量
class Poller : noncopyable
{
public:
typedef std::vector<Channel*> ChannelList;
Poller(EventLoop* loop);
virtual ~Poller();
virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0;
virtual void updateChannel(Channel* channel) = 0;
virtual void removeChannel(Channel* channel) = 0;
virtual bool hasChannel(Channel* channel) const;
protected:
typedef std::map<int, Channel*> ChannelMap;
ChannelMap channels_;
private:
EventLoop* ownerLoop_;
};
核心方法说明:不停的遍历是否有文件描述符就绪,如果有就绪的文件描述符,则将其加入到就绪队列中,然后交付给EventLoop去处理这些已经就绪的文件描述符
Timestamp Poller::poll(int timeoutMs, ChannelList* activeChannels)
{
int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
Timestamp now(Timestamp::now());
if (numEvents > 0) {
for (PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) {
if (pfd->revents > 0) {
--numEvents;
ChannelMap::const_iterator ch = channels_.find(pfd->fd);
Channel* channel = ch->second;
channel->set_revents(pfd->revents);
activeChannels->push_back(channel);
}
}
}
return now;
}
Channel模块
主要负责管理文件描述符与具体回调函数绑定,在事件发生的时候,调用对应的回调函数
class Channel : noncopyable
{
public:
typedef std::function<void()> EventCallback;
typedef std::function<void(Timestamp)> ReadEventCallback;
Channel(EventLoop* loop, int fd);
~Channel();
void handleEvent(Timestamp receiveTime);
void setReadCallback(ReadEventCallback cb);
void setWriteCallback(EventCallback cb);
void setCloseCallback(EventCallback cb);
void setErrorCallback(EventCallback cb);
void tie(const std::shared_ptr<void>&);
void enableReading();
void enableWriting();
void disableWriting();
void disableAll();
bool isNoneEvent() const;
bool isWriting() const;
bool isReading() const;
int fd() const;
int events() const;
void set_revents(int revt);
private:
void update();
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_;
bool logHup_;
bool tied_;
bool eventHandling_;
bool addedToLoop_;
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
};
核心方法,根据实际发生的事件类型,调用对应的回调函数,然后处理事件
void Channel::handleEvent(Timestamp receiveTime)
{
eventHandling_ = true;
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)) {
if (readCallback_) readCallback_(receiveTime);
}
if (revents_ & POLLOUT) {
if (writeCallback_) writeCallback_();
}
eventHandling_ = false;
}
测试
验证Channel的事件处理流程
观察EventLoop的创建与Channel之间的关系
测试源码
- 编译命令:g++ -g -I/home/muduo -I/home/muduo/net Channel_test.cpp -o Channel_test -L/home/muduo/lib -lmuduo_net -lmuduo_base
#include "muduo/net/Channel.h"
#include "muduo/net/EventLoop.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
using namespace muduo;
void handleRead(muduo::Timestamp receiveTime) {
std::cout << "Data received at " << receiveTime.toFormattedString() << std::endl;
}
int main() {
int listenFd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
bind(listenFd, (sockaddr*)&serverAddr, sizeof(serverAddr));
listen(listenFd, 5);
muduo::net::EventLoop loop;
muduo::net::Channel channel(&loop, listenFd);
channel.setReadCallback(handleRead);
channel.enableReading(); // 假设有这个方法来使能读事件
loop.loop();
return 0;