代码之家  ›  专栏  ›  技术社区  ›  Arkaitz Jimenez

epoll处于epollet模式,从插座读取前返回2个epoll in

  •  2
  • Arkaitz Jimenez  · 技术社区  · 16 年前

    epoll手册页指出,如果没有读取,则注册了epollet(边缘触发)的FD不应通知两次epollin。
    因此,在epollin之后,您需要清空缓冲区,然后epoll等待能够在新数据上返回新的epollin。

    但是,我在这种方法中遇到了一些问题,因为我看到了未接触FDS的重复epollin事件。
    这是strace输出,0x200是epollrdhup,它还没有在我的glibc头文件中定义,而是在内核中定义。

    30285 epoll_ctl(3, EPOLL_CTL_ADD, 9, {EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET|0x2000, {u32=9, u64=9}}) = 0
    30285 epoll_wait(3, {{EPOLLIN, {u32=9, u64=9}}}, 10, -1) = 1
    30285 epoll_wait(3, {{EPOLLIN, {u32=9, u64=9}}}, 10, -1) = 1
    30285 epoll_wait(3,  <unfinished ...>
    30349 epoll_ctl(3, EPOLL_CTL_DEL, 9, NULL) = 0
    30306 recv(9, "7u\0\0\10\345\241\312\t\20\f\32\r\10\27\20\2\30\200\10 \31(C0\17\32\r\10\27\20\2\30"..., 20000, 0) = 20000
    30349 epoll_ctl(3, EPOLL_CTL_DEL, 9, NULL) = -1 ENOENT (No such file or directory)
    30305 recv(9, " \31(C0\17\32\r\10\27\20\2\30\200\10 \31(C0\17\32\r\10\27\20\2\30\200\10 \31("..., 20000, 0) = 10011
    

    因此,在添加了fd编号9之后,在记录文件描述符之前,我确实收到了两个连续的epollin事件,syscall跟踪显示了我如何在读取之前删除fd,但它只会发生一次,每个事件一次。
    因此,要么我没有正确阅读手册页,要么有什么东西正在这里工作。

    3 回复  |  直到 15 年前
        1
  •  7
  •   caf    16 年前

    我想你错过了 epoll 手册页:

    因为即使边缘被触发 可以生成epoll多个事件 收到多块 数据,调用者可以选择 指定 EPOLLONESHOT 标记,收件人 告诉epoll禁用关联的 接收后的文件描述符 与…有关的事件 epoll_wait(2) . 什么时候? 这个 电子枪 已指定标志, 打电话的人有责任 使用重新排列文件描述符 epoll_ctl(2) 具有 EPOLL_CTL_MOD .

    即:在第一个接收队列之前,有两个数据块到达接收队列 read() 发生了,这意味着你有两个epoll事件。看起来像 电子枪 是您所追求的,这将在事件发生时自动从轮询集中删除文件描述符(因此您不需要执行 EPOLL_CTL_DEL )

        2
  •  2
  •   nos    16 年前

    边缘触发器只是意味着(除非您使用了epolloneshot),当某个东西进入(内核)缓冲区时,您将得到1个事件。

    因此,如果您得到1个epollin事件而不采取任何措施,那么在下一次某些数据到达该描述符时,您将得到另一个epollin—如果没有新数据到达,那么您将不会得到一个事件,即使您没有按照第一个事件的指示读取任何数据。

        3
  •  0
  •   Josh Paul    15 年前

    简单地说,epolloneshot只是意味着如果你不读取你应该读取的数据,它们就会被丢弃。

    通常情况下,如果你不阅读相同的数据,你会收到一个事件的通知。然而,使用epolloneshot,不读取数据是完全合法的,它们将被忽略。因此,不会生成其他事件。