epoll封装成类

epoll封装成类

epoll基本信息

epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并
发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结
果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点
原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件 异步唤醒而加入Ready队列的描述符集合就行了。
目前epell是linux大规模并发网络程序中的热门首选模型。 epoll除了提供 select/ poll那种
IO事件的电平触发(Level Triggered)外,还提 供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存
IO状态,减少 epoll_wait/epoll_pwait的调用,提高应用程序效率。

三个函数

int epoll_create(int size)

创建一个epoll句柄,参数size用来告诉内核监听的文件描述符个数,跟内存大小有

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

控制某个epoll监控的文件描述符上的事件:注册、修改、删除
epfd: epoll_create(int size)返回的句柄(根节点)
op:
EPOLL_CTL_ADD(注册新的fd到epfd),
EPOLL_CTL_MOD(修改已经注册的fd的监听事件),
EPOLL_CTL_DEL(从epfd删除一个fd);
fd:
op 实施的对象
event:
告诉内核需要监听的事件
struct epoll_event {
__uint32_t events; /* Epoll events

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一种可能的实现方式。 首先,我们需要定义一个名为 `EpollWrapper` 的类,并且包含以下成员函数: ```cpp class EpollWrapper { public: EpollWrapper(); ~EpollWrapper(); int add(int fd, uint32_t events); int modify(int fd, uint32_t events); int remove(int fd); int wait(int timeout_ms, epoll_event* events, int max_events); int close(); private: int epoll_fd_; }; ``` 其中,`add()` 函数用于向 epoll 实例中添加一个文件描述符及其对应的事件类型,`modify()` 函数用于修改已添加的文件描述符对应的事件类型,`remove()` 函数用于从 epoll 实例中移除一个文件描述符,`wait()` 函数用于等待事件就绪并返回就绪的文件描述符,`close()` 函数用于关闭 epoll 实例。 接下来,我们可以实现这些成员函数。首先是构造函数和析构函数: ```cpp EpollWrapper::EpollWrapper() { epoll_fd_ = epoll_create1(0); if (epoll_fd_ == -1) { throw std::runtime_error("Failed to create epoll instance"); } } EpollWrapper::~EpollWrapper() { close(); } ``` 构造函数中使用 `epoll_create1()` 函数创建一个 epoll 实例,并且检查返回值以确保实例创建成功。析构函数中调用 `close()` 函数以关闭 epoll 实例。 接下来,我们可以实现 `add()`、`modify()`、`remove()`、`wait()` 和 `close()` 函数: ```cpp int EpollWrapper::add(int fd, uint32_t events) { epoll_event event; event.data.fd = fd; event.events = events; return epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event); } int EpollWrapper::modify(int fd, uint32_t events) { epoll_event event; event.data.fd = fd; event.events = events; return epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &event); } int EpollWrapper::remove(int fd) { return epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr); } int EpollWrapper::wait(int timeout_ms, epoll_event* events, int max_events) { return epoll_wait(epoll_fd_, events, max_events, timeout_ms); } int EpollWrapper::close() { int ret = 0; if (epoll_fd_ != -1) { ret = ::close(epoll_fd_); epoll_fd_ = -1; } return ret; } ``` 这些函数中,`add()`、`modify()` 和 `remove()` 函数都是通过调用 `epoll_ctl()` 函数来实现的,`wait()` 函数则是通过调用 `epoll_wait()` 函数来等待就绪的事件,`close()` 函数则是通过调用 `::close()` 函数来关闭 epoll 实例。 最后,我们需要编写单元测试来验证我们的实现是否正确。我们可以使用 Google Test 框架来编写单元测试。以下是一个简单的单元测试示例: ```cpp #include <gtest/gtest.h> #include <sys/socket.h> #include <sys/epoll.h> #include <unistd.h> #include "epoll_wrapper.h" TEST(EpollWrapperTest, Basic) { EpollWrapper epoll; ASSERT_TRUE(epoll.add(STDIN_FILENO, EPOLLIN) == 0); int pipe_fds[2]; ASSERT_TRUE(pipe(pipe_fds) == 0); ASSERT_TRUE(epoll.add(pipe_fds[0], EPOLLIN) == 0); epoll_event events[2]; int ret = epoll.wait(1000, events, 2); ASSERT_TRUE(ret >= 0); for (int i = 0; i < ret; ++i) { if (events[i].data.fd == STDIN_FILENO) { char buf[1024]; int n = read(STDIN_FILENO, buf, sizeof(buf)); ASSERT_TRUE(n >= 0); } else if (events[i].data.fd == pipe_fds[0]) { char buf[1024]; int n = read(pipe_fds[0], buf, sizeof(buf)); ASSERT_TRUE(n >= 0); } } ASSERT_TRUE(epoll.remove(STDIN_FILENO) == 0); ASSERT_TRUE(epoll.remove(pipe_fds[0]) == 0); close(pipe_fds[0]); close(pipe_fds[1]); } ``` 在这个单元测试中,我们首先创建了一个 `EpollWrapper` 实例,然后向其中添加标准输入(`STDIN_FILENO`)和一个管道读端的文件描述符,并且等待这些文件描述符上的事件就绪。如果在等待过程中发生错误,单元测试会失败。如果等待成功,则断言返回的就绪事件个数大于等于 0。然后,我们可以遍历就绪事件,读取就绪的文件描述符中的数据并且进行断言。最后,我们移除已添加的文件描述符,并且关闭管道。 这就是一个可能的 C++ epoll/poll 封装类及单元测试的实现方式。当然,这只是一种参考,具体的实现方式可能因应用场景不同而不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值