一、poller抽象类
Poller是抽象类
为什么muduo库要抽象一层Poller?
因为在eventloop里面,在使用I/O复用的时候,并没有直接指定epoll,因为muduo库对外提供I/O复用的能力有2个:1个是poll,1个是epoll,在eventloop里面,不可能直接去使用poll或者epoll。
从抽象层面直接使用抽象类poller,到时候引用不同的派生类对象,调用同名覆盖方法,就可以非常方便地去扩展不同的I/O复用能力,此时的Poller就是一个多路分发器。
类前置声明和包含头文件区别
classB;
classA{
public:
B b;
};
classB{
public:
A a;
};
B用到A,A用到B,这样会发生错误,解决办法只需要把其中的一个A类中的B类型成员改成指针形式就可以避免这个无限延伸的怪圈了,为什么,因为一个指针是有具体空间大小,虽然它指向的空间不一定是多大,那么这个类的大小就可以被确定了
poller监听的就是eventloop保存的那些channel
protected的成员变量就是让派生类可以访问到,private的成员变量派生类不能访问到。
DefaultPoller.cc
获取环境变量
#include "Poller.h"
#include "EPollPoller.h"
#include <stdlib.h>
//包含了具体实现类的头文件
Poller* Poller::newDefaultPoller(EventLoop *loop)
{
if (::getenv("MUDUO_USE_POLL"))
{
return nullptr;//生成poll的实例
}
else
{
return new EPollPoller(loop);//生成epoll的实例
}
}
二、EPollPoller
EPollPoller的主要实现:作为poller的派生类,把基类给派生类保留的这些纯虚函数的接口实现出来。
1、重写基类poller的抽象方法
2、
epollfd_
#pragma once
#include "Poller.h"
#include "Timestamp.h"
#include <vector>
#include <sys/epoll.h>
class Channel;
/**
* epoll的使用,创建epoll,往epoll添加时间,然后等待,最后删除
* epoll_create
* epoll_ctl add/mod/del
* epoll_wait
*/
class EPollPoller : public Poller
{
private:
//给vector初始的长度
static const int kInitEventListSize = 16;
// 填写活跃的连接
void fillActiveChannels(int numEvents, ChannelList *activeChannels) const;
// 更新channel通道
void update(int operation, Channel *channel);
using EventList = std::vector<epoll_event>;
int epollfd_;
EventList events_;
public:
EPollPoller(EventLoop *loop);
~EPollPoller() override;
// 重写基类Poller的抽象方法
Timestamp poll(int timeoutMs, ChannelList *activeChannels) override;
void updateChannel(Channel *channel) override;
void removeChannel(Channel *channel) override;
};
#include "EPollPoller.h"
#include "Logger.h"
#include "Channel.h"
#include <errno.h>
#include <unistd.h>
#include <strings.h>
//下面这三个是三个状态,是用数字表示的
// channel未添加到poller中
const int kNew = -1; // channel的成员index_ = -1
// channel已添加到poller中
const int kAdded = 1;
// channel从poller中删除
const int kDeleted = 2;
EPollPoller::EPollPoller(EventLoop *loop)
: Poller(loop)
, epollfd_(::epoll_create1(EPOLL_CLOEXEC))//epoll_create1是一个create epoll的一个函数,后面是个宏定义
, events_(kInitEventListSize) // vector<epoll_event> 用一个数初始化vector大小
{
if (epollfd_ < 0)
{
LOG_FATAL("epoll_create error:%d \n", errno);
}
}
EPollPoller::~EPollPoller()
{
::close(epollfd_);
}
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
// 实际上应该用LOG_DEBUG输出日志更为合理
LOG_INFO("func=%s => fd total count:%lu \n", __FUNCTION__, channels_.size());
int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs);
int saveErrno = errno;
Timestamp now(Timestamp::now());
if (numEvents > 0)
{
LOG_INFO("%d events happened \n", numEvents);
fillActiveChannels(numEvents, activeChannels);
if (numEvents == events_.size())
{
events_.resize(events_.size() * 2);
}
}
else if (numEvents == 0)
{
LOG_DEBUG("%s timeout! \n", __FUNCTION__);
}
else
{
if (saveErrno != EINTR)
{
errno = saveErrno;
LOG_ERROR("EPollPoller::poll() err!");
}
}
return now;
}
// channel update remove => EventLoop updateChannel removeChannel => Poller updateChannel removeChannel
/**
* EventLoop => poller.poll
* ChannelList Poller
* ChannelMap <fd, channel*> epollfd
*/
void EPollPoller::updateChannel(Channel *channel)
{
const int index = channel->index();
LOG_INFO("func=%s => fd=%d events=%d index=%d \n", __FUNCTION__, channel->fd(), channel->events(), index);
if (index == kNew || index == kDeleted)
{
if (index == kNew)
{
int fd = channel->fd();
channels_[fd] = channel;
}
channel->set_index(kAdded);
update(EPOLL_CTL_ADD, channel);
}
else // channel已经在poller上注册过了
{
int fd = channel->fd();
if (channel->isNoneEvent())
{
update(EPOLL_CTL_DEL, channel);
channel->set_index(kDeleted);
}
else
{
update(EPOLL_CTL_MOD, channel);
}
}
}
// 从poller中删除channel
void EPollPoller::removeChannel(Channel *channel)
{
int fd = channel->fd();
channels_.erase(fd);
LOG_INFO("func=%s => fd=%d\n", __FUNCTION__, fd);
int index = channel->index();
if (index == kAdded)
{
update(EPOLL_CTL_DEL, channel);
}
channel->set_index(kNew);
}
// 填写活跃的连接
void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const
{
for (int i=0; i < numEvents; ++i)
{
Channel *channel = static_cast<Channel*>(events_[i].data.ptr);
channel->set_revents(events_[i].events);
activeChannels->push_back(channel); // EventLoop就拿到了它的poller给它返回的所有发生事件的channel列表了
}
}
// 更新channel通道 epoll_ctl add/mod/del
void EPollPoller::update(int operation, Channel *channel)
{
epoll_event event;
bzero(&event, sizeof event);
int fd = channel->fd();
event.events = channel->events();
event.data.fd = fd;
event.data.ptr = channel;
if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)
{
if (operation == EPOLL_CTL_DEL)
{
LOG_ERROR("epoll_ctl del error:%d\n", errno);
}
else
{
LOG_FATAL("epoll_ctl add/mod error:%d\n", errno);
}
}
}
overirde表示在派生类里面,这些方法是覆盖方法。必须由编译器来保证在基类里面一定有这些函数的接口的声明。在派生类要重写他们。
给EPollPoller的析构函数写overide,就是让编译器给你检查基类的析构一定是虚函数。
底层是vector,放eventlist,可以动态地扩容。
成员变量的epollfd要通过epoll_create来创建,映射的就是epoll底层的文件系统