epoll详解

epoll-I / O事件通知工具。使用前需引用 头文件#include <sys / epoll.h>

epoll API执行与poll类似的任务:监视多个文件描述符,以查看是否可以在任何文件描述符上进行I / O。 epoll API可以用作边缘触发或级别触发的接口,并且可以很好地扩展到大量监视的文件描述符。提供了以下系统调用来创建和管理epoll实例:

       ①epoll_create创建一个epoll实例并返回引用该实例的文件描述符。

       ②然后通过epoll_ctl注册对特定文件描述符的兴趣。当前在epoll实例上注册的文件描述符集有时称为epoll集。

       ③epoll_wait等待I / O事件,如果当前没有可用的事件,则阻塞调用线程。

侦听器是一个非阻塞套接字,已在其上调用listen。

建议用法示例:
        尽管将epoll用作级别触发接口时确实具有与poll相同的语义,但是边缘触发的用法需要更多说明,以避免应用程序事件循环中的停顿。 在此示例中,侦听器是一个非阻塞套接字,已在其上调用listen。 函数do_use_fd使用新的就绪文件描述符,直到EAGAIN由read或write返回。 事件驱动的状态机应用程序应在收到EAGAIN后记录其当前状态,以便在下一次对do_use_fd的调用时,它将继续从其先前停止的位置读取或写入。

#define MAX_EVENTS 10
           struct epoll_event ev, events[MAX_EVENTS];
           int listen_sock, conn_sock, nfds, epollfd;

           /* Set up listening socket, 'listen_sock' (socket(),
              bind(), listen()) */

           epollfd = epoll_create(10);
           if (epollfd == -1) {
               perror("epoll_create");
               exit(EXIT_FAILURE);
           }

           ev.events = EPOLLIN;
           ev.data.fd = listen_sock;
           if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
               perror("epoll_ctl: listen_sock");
               exit(EXIT_FAILURE);
           }

           for (;;) {
               nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
               if (nfds == -1) {
                   perror("epoll_pwait");
                   exit(EXIT_FAILURE);
               }

               for (n = 0; n < nfds; ++n) {
                   if (events[n].data.fd == listen_sock) {
                       conn_sock = accept(listen_sock,
                                       (struct sockaddr *) &local, &addrlen);
                       if (conn_sock == -1) {
                           perror("accept");
                           exit(EXIT_FAILURE);
                       }
                       setnonblocking(conn_sock);
                       ev.events = EPOLLIN | EPOLLET;
                       ev.data.fd = conn_sock;
                       if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                                   &ev) == -1) {
                           perror("epoll_ctl: conn_sock");
                           exit(EXIT_FAILURE);
                       }
                   } else {
                       do_use_fd(events[n].data.fd);
                   }
               }
           }


当用作边缘触发接口时,出于性能原因,可以通过指定(EPOLLIN | EPOLLOUT)在epoll接口(EPOLL_CTL_ADD)中添加一次文件描述符。 这样可以避免在EPOLLIN和EPOLLOUT之间连续切换,并使用EPOLL_CTL_MOD调用epoll_ctl。

问题和解答:
       Q0:用于区分epoll集中注册的文件描述符的密钥是什么?

       A0:密钥是文件描述符号和打开文件描述(也称为“打开文件句柄”,即打开文件的内核的内部表示)的组合。

       Q1:如果在epoll实例上两次注册相同的文件描述符,会发生什么情况?

       A1:您可能会得到EEXIST。但是,可以将重复的(dup,dup2,fcntl  F_DUPFD)描述符添加到同一epoll实例。如果重复的文件描述符使用不同的事件掩码注册,则这对于筛选事件可能是一种有用的技术。

       Q2:两个epoll实例可以等待相同的文件描述符吗?如果是,事件是否同时报告给两个epoll文件描述符?

       A2:是的,事件将报告给这两个事件。但是,可能需要仔细编程才能正确执行此操作。

       Q3:epoll文件描述符本身是否可以 poll/epoll/selectable?

       A3:是的。如果epoll文件描述符有等待事件,则它将指示为可读。

       Q4:如果尝试将epoll文件描述符放入其自己的文件描述符集中会发生什么?

       A4:epoll_ctl调用将失败(EINVAL)。但是,您可以在另一个epoll文件描述符集中添加一个epoll文件描述符。

       Q5:我可以通过UNIX域套接字将epoll文件描述符发送到另一个进程吗?

       A5:是的,但是这样做没有意义,因为接收过程在epoll集中将没有文件描述符的副本。

       Q6:关闭文件描述符会导致它自动从所有epoll集中删除吗?

       A6:是,但是请注意以下几点。文件描述符是对打开文件描述的引用(请参见open(2))。每当描述符是通过dup,dup2,fcntl F_DUPFD或fork复制,将创建一个引用相同打开文件描述的新文件描述符。开放文件描述将继续存在,直到所有引用它的文件描述符都已关闭。仅在关闭所有引用基础打开文件描述的文件描述符之后(或者如果使用epoll_ctl(2)EPOLL_CTL_DEL明确删除了描述符之后),才从epoll集中删除文件描述符。这意味着即使关闭了作为epoll集一部分的文件描述符,如果其他引用相同基础文件描述的文件描述符保持打开状态,则可能会报告该文件描述符的事件。

       Q7:如果在epoll_wait(2)调用之间发生多个事件,它们是合并还是分开报告?

       A7:他们将被合并。

       Q8:对文件描述符的操作是否会影响已收集但尚未报告的事件?

       A8:您可以对现有文件描述符执行两项操作。在这种情况下,删除将毫无意义。修改将重新读取可用的I / O。

       Q9:使用EPOLLET标志(边沿触发的行为)时,我是否需要连续读写文件描述符直到EAGAIN?

       A9:从epoll_wait(2)接收事件应向您建议该文件描述符已准备就绪,可以执行请求的I / O操作。您必须考虑到它准备就绪,直到下一次(非阻塞)读/写产生EAGAIN为止。何时以及如何使用文件描述符完全取决于您。对于面向数据包/令牌的文件(例如,数据报套接字,标准模式下的终端),检测读/写I / O空间结束的唯一方法是继续读/写直到EAGAIN。对于面向流的文件(例如管道,FIFO,流套接字),还可以通过检查从目标文件描述符读取/写入到目标文件描述符的数据量来检测读取/写入I / O空间已用尽的情况。例如,如果通过要求读取一定数量的数据来调用read(2),而read(2)返回的字节数较少,则可以确定已经用完了文件描述符的读取I / O空间。使用write(2)进行写入时也是如此。 (如果不能保证受监视的文件描述符始终引用面向流的文件,请避免使用后一种技术。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值