Epoll和超时问题

5
我正在使用 epoll 来管理大约 20 到 30 个套接字。 我了解到 epoll_wait 可以用于等待其中一个套接字上的数据到达,但我不知道如何在套接字级别实现超时。 我可以在 epoll_wait 上使用超时,但在我的情况下它并不是非常有用。 例如,如果我需要关闭一条记录了 > 500 毫秒没有活动的套接字或者每 200 毫秒向套接字发送一些数据,无论如何都要执行该操作。 如何使用 epoll 实现这些套接字级别的超时呢?非常感谢您的任何建议和想法!
谢谢, Shivam Kalra
2个回答

12
尝试将每个套接字与计时器文件描述符对象(timerfd_create)配对。对于应用程序中的每个套接字,创建一个计时器,最初设置为在500毫秒后到期,并将计时器添加到epoll对象中(与套接字一样--通过epoll_ctlEPOLL_CTL_ADD)。然后,每当数据到达一个套接字时,重置该套接字的关联计时器回到500毫秒的超时时间。
如果计时器到期(因为套接字已经500毫秒没有活动了),则计时器将在epoll对象中变为“可读就绪”,并使任何等待epoll_wait的线程唤醒。然后,该线程可以处理计时器的关联套接字的超时。

6
听起来你正在尝试编写一个事件循环(如果是这样,请顺便看一下libev)。epoll 在那里不会有帮助,你必须自己跟踪套接字的不活动状态(例如clock_gettime()gettimeofday()),然后每秒唤醒几次并检查所需的所有内容。
一些伪代码。
while (1) {
    n = epoll_wait(..., 5);
    if (n > 0) {
        /* process activity */
    } else {
        /* process inactivity */
    }
}

这将每秒唤醒您200次,如果所有套接字都处于非活动状态。
非活动检查需要一个要检查的套接字列表以及最后一次非活动的时间戳:
struct sockstamp_s {
    /* socket descriptor */
    int sockfd;
    /* last active */
    struct timeval tv;
};

/* check which socket has been inactive */
for (struct sockstamp_s *i = socklist; ...; i = next(i)) {
    if (diff(s->tv, now()) > 500) {
        /* socket s->sockfd was inactive for more than 500 ms */
        ...
    }
}

diff()函数返回两个struct timeval结构体之间的时间差,而now()函数则返回当前时间戳。


谢谢回复。但是,我在想,如果我能够使用 epoll 等待不活动检查并等待非常短的时间,比如大约 10 毫秒,那么我是否可以获得比 select + 不活动检查更好的性能提升呢? - Shivam
取决于情况,你越频繁唤醒CPU的次数就越多。此外,你需要一个1000 HZ的内核才能每毫秒唤醒一次。正如我所说,我强烈建议使用准备好的事件循环(例如libev或libevent),它们针对这些情况进行了优化(代价是依赖性)。 - hroptatyr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接