如何使用 epoll(void* event.data.ptr) 管理 Connection 的生命周期

How to manage the life cycle of Connection using epoll(void* event.data.ptr)

本文关键字:管理 Connection 周期 生命 ptr data epoll 何使用 void event      更新时间:2023-10-16

我正在使用C++实现epoll。 我想学习nginx使用(void*) event.data.ptrConnection相关联。Connection是一个聪明的指针。但是在void*之间,我需要将智能指针转换为原始指针。

在转换和获取过程中,引用的数量没有增加,这显然是程序会崩溃的。 所以我不使用智能指针。

我使用newdelete.但它太可怕了。
如何管理Connection的生命周期?

int nfds = epoll_wait(epollfd, event_list, 100, -1);
for (int n = 0; n < nfds; ++n) {
auto event = event_list[n];
auto revents = event.events;
if (revents & EPOLLIN) {
if (event.data.fd  == listen_fd_) {
int fd = handleAccept(listen_fd_);
auto conn_ptr = std::make_shared<Connection>(fd, connections_manager_);
//connecions_manager_ is std::set<std::shared_ptr<Connection>>
//it use start, stop and stop_all manage Connection.
connections_manager_.start(conn_ptr);
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.ptr = static_cast<void*>(conn_ptr.get());
if (epoll_ctl(event_.getEpollFd(), EPOLL_CTL_ADD, fd, &ev) == -1) {
std::cout << "epoll_ctl failed. fd is " << fd << 'n';
perror("epoll_ctl: fd_");
exit(EXIT_FAILURE);
}
continue;
}
auto conn = static_cast<Connection *>(event.data.ptr);
conn->start();
}
}

以下是您可能想要实现的一般想法:

  • 保留您创建的所有Connection对象的列表。一个简单的C式数组就可以了,但你可以检查使用std::vectorstd::mapstd::unordered_map来记Connection对象的可能性。
  • 每当创建新Connection时,您都会先将其添加到列表中,然后再将其添加到epoll池中。我建议为此add()单独的方法。
  • 同样,在关闭Connection(从主机或客户端)时,需要将其从池中删除epoll。但是,它将在您的连接列表中。您可能需要一个标志,例如isClosed并将其设置为true以关闭连接。不要删除epoll主事件循环中的Connection对象。此外,在关闭连接之前,您需要一些东西来确定是否还有一些数据要发送。客户端可能正在等待从服务器接收数据。
  • 对于这些已关闭连接的垃圾回收,您可以使用具有固定时间间隔的单独线程来浏览列表并删除已关闭的连接。

一般来说,你可能需要一些包装方法来分解你的操作,waitlistenaddremove等。它会更容易管理。此外,您可能有专用于读/写操作的单独线程池。在主事件循环中接受连接就好了。

希望对您有所帮助!
如果您想进一步讨论,请告诉我。