【muduo库学习】实现最简单的reactor模式
来源:互联网 发布:mac os x 10.11 下载 编辑:程序博客网 时间:2024/05/21 17:15
《linux多线程服务端编程 使用muduo c++网络库》的第8章是从0开始讲述一个网络库的实现,比较适合初学者入门。
在本书的第8章中是实现了以下几个类:eventloop类,poller类,channel类
首先分析channel类的定义:
#ifndef MUDUO_NET_CHANNEL_H#define MUDUO_NET_CHANNEL_H#include <boost/function.hpp>#include <boost/noncopyable.hpp>namespace muduo{class EventLoop;////// A selectable I/O channel.////// This class doesn't own the file descriptor./// The file descriptor could be a socket,/// an eventfd, a timerfd, or a signalfdclass Channel : boost::noncopyable{ public: typedef boost::function<void()> EventCallback; Channel(EventLoop* loop, int fd); void handleEvent(); void setReadCallback(const EventCallback& cb) { readCallback_ = cb; } void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; } void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; } int fd() const { return fd_; } int events() const { return events_; } void set_revents(int revt) { revents_ = revt; } bool isNoneEvent() const { return events_ == kNoneEvent; } void enableReading() { events_ |= kReadEvent; update(); } // void enableWriting() { events_ |= kWriteEvent; update(); } // void disableWriting() { events_ &= ~kWriteEvent; update(); } // void disableAll() { events_ = kNoneEvent; update(); } // for Poller int index() { return index_; } void set_index(int idx) { index_ = idx; } EventLoop* ownerLoop() { return loop_; } private: void update(); static const int kNoneEvent; static const int kReadEvent; static const int kWriteEvent; EventLoop* loop_; const int fd_; int events_; int revents_; int index_; // used by Poller. EventCallback readCallback_; EventCallback writeCallback_; EventCallback errorCallback_;};}#endif // MUDUO_NET_CHANNEL_Hfd_是channel类的私有变量,一个channel对象是跟文件句柄fd直接挂钩的。channel类的构造函数是需要loop 和 fd两个参数,因此每一个关注的fd都会创建一个专门的channel对象来对其负责。
接下来看看poller类的定义:
class Poller : boost::noncopyable{ public: typedef std::vector<Channel*> ChannelList; Poller(EventLoop* loop); ~Poller(); /// Polls the I/O events. /// Must be called in the loop thread. Timestamp poll(int timeoutMs, ChannelList* activeChannels); /// Changes the interested I/O events. /// Must be called in the loop thread. void updateChannel(Channel* channel); void assertInLoopThread() { ownerLoop_->assertInLoopThread(); } private: void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; typedef std::vector<struct pollfd> PollFdList; typedef std::map<int, Channel*> ChannelMap; EventLoop* ownerLoop_; PollFdList pollfds_; ChannelMap channels_;};}#endif // MUDUO_NET_POLLER_H
poller类的实现
#include "Poller.h"#include "Channel.h"#include "logging/Logging.h"#include <assert.h>#include <poll.h>using namespace muduo;Poller::Poller(EventLoop* loop) : ownerLoop_(loop){}Poller::~Poller(){}Timestamp Poller::poll(int timeoutMs, ChannelList* activeChannels){ // XXX pollfds_ shouldn't change int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); Timestamp now(Timestamp::now()); if (numEvents > 0) { LOG_TRACE << numEvents << " events happended"; fillActiveChannels(numEvents, activeChannels); } else if (numEvents == 0) { LOG_TRACE << " nothing happended"; } else { LOG_SYSERR << "Poller::poll()"; } return now;}void Poller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const{ 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); assert(ch != channels_.end()); Channel* channel = ch->second; assert(channel->fd() == pfd->fd); channel->set_revents(pfd->revents); // pfd->revents = 0; activeChannels->push_back(channel); } }}void Poller::updateChannel(Channel* channel){ assertInLoopThread(); LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); if (channel->index() < 0) { // a new one, add to pollfds_ assert(channels_.find(channel->fd()) == channels_.end()); struct pollfd pfd; pfd.fd = channel->fd(); pfd.events = static_cast<short>(channel->events()); pfd.revents = 0; pollfds_.push_back(pfd); int idx = static_cast<int>(pollfds_.size())-1; channel->set_index(idx); channels_[pfd.fd] = channel; } else { // update existing one assert(channels_.find(channel->fd()) != channels_.end()); assert(channels_[channel->fd()] == channel); int idx = channel->index(); assert(0 <= idx && idx < static_cast<int>(pollfds_.size())); struct pollfd& pfd = pollfds_[idx]; assert(pfd.fd == channel->fd() || pfd.fd == -1); pfd.events = static_cast<short>(channel->events()); pfd.revents = 0; if (channel->isNoneEvent()) { // ignore this pollfd pfd.fd = -1; } }}
poller对象是有pollfdlist,channels这样的私有成员。在poller::updatechannel中,会把channel对象中的fd抽取出来,组成pollfd结构体,然后添加到pollfds_数组中。并且会对pollfdlist,channels等私有成员进行相应的修改,所以poller::update是将channel和poll联系起来的关键函数。
而在poller::poll中则会调用poll系统调用来完成关心事件的IO多路复用,并且将当前有活动的事件添加到activechannels中。
最后在eventloop::loop()中会调用相应事件的处理方法:
void EventLoop::loop(){ assert(!looping_); assertInLoopThread(); looping_ = true; quit_ = false; while (!quit_) { activeChannels_.clear(); poller_->poll(kPollTimeMs, &activeChannels_); for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { (*it)->handleEvent(); } } LOG_TRACE << "EventLoop " << this << " stop looping"; looping_ = false;}
通过以上几个简单的类,即可实现最简单的reactor模式。
再来看简单的测试程序:
#include "Channel.h"#include "EventLoop.h"#include <stdio.h>#include <sys/timerfd.h>muduo::EventLoop* g_loop;void timeout(){ printf("Timeout!\n"); g_loop->quit();}int main(){ muduo::EventLoop loop; g_loop = &loop; int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); muduo::Channel channel(&loop, timerfd); channel.setReadCallback(timeout); channel.enableReading(); struct itimerspec howlong; bzero(&howlong, sizeof howlong); howlong.it_value.tv_sec = 5; ::timerfd_settime(timerfd, 0, &howlong, NULL); loop.loop(); ::close(timerfd);}
上述程序中是将timerfd交由eventloop管理,并且编写其handler函数timeout()。eventloop会完成事件的检测和分发。
0 0
- 【muduo库学习】实现最简单的reactor模式
- muduo的reactor模式基本实现
- muduo网络库学习笔记(9):Reactor模式的关键结构
- Reactor 模式的简单实现
- muduo源码分析--Reactor模式的在muduo中的使用(二)
- muduo源码分析--Reactor模式在muduo中的使用
- muduo reactor
- POCO实现的reactor模式
- 使用c++简单实现reactor模式
- 使用c++简单实现reactor模式
- Reactor模式简单实现与理解
- muduo简化(1):Reactor的关键结构
- 简单的ACE反应器(Reactor)模式服务器
- muduo网络库学习笔记(5):线程池的实现
- muduo网络库学习笔记(10):定时器的实现
- 从epoll构建muduo-2 最简单的epoll
- 从epoll构建muduo-2 最简单的epoll
- epoll实现Reactor模式
- Remote System Explorer Operation卡死Eclipse解决方案
- logback 入门学习(二)
- Cannot change version of project facet Dynamic web 3.0
- js 更改URL参数
- Java使用imageio 读写图像
- 【muduo库学习】实现最简单的reactor模式
- Spark性能调优——基础篇
- 字典树
- 根据邓白氏号码查询公司信息
- JavaScript 正则表达式与字符串查找
- 开发的本质 从更高点看软件开发的侧重点
- 排序方法
- Red Hat Linux系统安装配置Oracle11g R2 RAC (ASM)数据库
- 单例(GCD:dispatch_once)