找工作小项目:day15-macOS支持、完善逻辑

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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值