c++ epoll poll封装成类并写出单元测试
时间: 2023-06-29 18:17:22 浏览: 61
好的,我可以为您提供一种可能的实现方式。
首先,我们需要定义一个名为 `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 封装类及单元测试的实现方式。当然,这只是一种参考,具体的实现方式可能因应用场景不同而不同。