macOS支持、完善逻辑
目前的代码可以在Linux上完美运行编译,在Windows上也可以通过WSL编译运行源代码,但是在MacBook上却无法运行编译,这主要是由于macOS上没有epoll,取而代之的很相似的kqueue。由于操作系统不同,我们需要的是在面向操作系统即从用户态向内核态转变时进行修改。目前我们面向这一过程的仅有Epoll,所以在面向不同操作系统的过程中仅需要关心这部分。
为了完善逻辑处理机制,即将不同事件类型进行不同的注册,事件注册在Channel中完成,因为之前是在Channel对不同事件的回调函数进行设置的。
1、错误检测机制
2、Macros(宏定义,去除类移动和复制)
3、Socket(创建地址和socket)
4、Epoll->Poller(事件注册分发从以及红黑树上删除)
声明部分就可以很直观地看出来,两者同属一系,仅仅是多了一部分适用于macOS的定义。
//Epoll
#include "Macros.h"
#include <vector>
#ifdef OS_LINUX
#include <sys/epoll.h>
#endif
class Channel;
class Epoll {
public:
Epoll();
~Epoll();
DISALLOW_COPY_AND_MOVE(Epoll);
void UpdateChannel(Channel *ch);
void DeleteChannel(Channel *ch);
std::vector<Channel *> Poll(int timeout = -1);
private:
int epfd_{
1};
struct epoll_event *events_{
nullptr};
};
//Poller
#include "Macros.h"
#ifdef OS_LINUX
#include <sys/epoll.h>
#endif
#ifdef OS_MACOS
#include <sys/event.h>
#endif
class Channel;
class Poller {
public:
Poller();
~Poller();
DISALLOW_COPY_AND_MOVE(Poller);
void UpdateChannel(Channel *ch);
void DeleteChannel(Channel *ch);
std::vector<Channel *> Poll(int timeout = -1);
private:
int fd_{
1};
#ifdef OS_LINUX
struct epoll_event *events_{
nullptr};
#endif
#ifdef OS_MACOS
struct kevent *events_{
nullptr};
#endif
};
为了完善逻辑,能够为不同事件类型注册不同的事件处理方式,这里采用标志位的方案进行设置,由于多了一种系统所以代码量会多出一倍,这是因为需要对在macOS系统下也进行定义。
在poll中对就绪事件进行分发,利用Channel能够在使用fd的同时获得事件的处理方式。
std::vector<Channel *> Poller::Poll(int timeout) {
std::vector<Channel *> active_channels;
int nfds = epoll_wait(fd_, events_, MAX_EVENTS, timeout);
ErrorIf(nfds == -1, "epoll wait error");
for (int i = 0; i < nfds; ++i) {
Channel *ch = (Channel *)events_[i].data.ptr;
int events = events_[i].events;
if (events & EPOLLIN) {
ch->SetReadyEvents(Channel::READ_EVENT);
}
if (events & EPOLLOUT) {
ch->SetReadyEvents(Channel::WRITE_EVENT);
}
if (events & EPOLLET) {
ch->SetReadyEvents(Channel::ET);
}
active_channels.push_back(ch);
}
return active_channels;
}
之后是对Channel中的监听事件类型标志位进行设置,如果事件标志位判断为真则将该事件设置成对应标志,注意是对红黑树树上的通道进行设置,不在树上都需要放到树上。
注意就绪事件和监听事件之间的关系,
注册监听:程序首先通过 listen_events_ 向内核注册自己感兴趣的事件。
内核监控:内核不断监控这些事件,并在事件发生时通知程序。
事件就绪:当内核检测到某些事件发生时,会将这些事件标记为就绪,并通过 I/O 多路复用机制返回给应用程序。
处理事件:程序读取 ready_events_,了解具体哪些事件已发生,然后进行相应的处理。
void Poller::UpdateChannel(Channel *ch) {
int sockfd = ch->GetSocket()->GetFd();
struct epoll_event ev {
};
ev.data.ptr = ch;
if (ch->GetListenEvents() & Channel::READ_EVENT) {
ev.events |= EPOLLIN | EPOLLPRI;
}
if (ch->GetListenEvents() & Channel

最低0.47元/天 解锁文章
1174

被折叠的 条评论
为什么被折叠?



