实例浅析epoll的水平触发和边缘触发

论坛 期权论坛     
选择匿名的用户   2021-5-22 15:22   73   0
<p><strong>一.基本概念                                                         </strong></p>
<p>我们通俗一点讲:</p>
<p>Level_triggered(水平触发): 当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小), 那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!</p>
<p>Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!</p>
<p>阻塞IO:当你去读一个阻塞的文件描述符时,如果在该文件描述符上没有数据可读,那么它会一直阻塞(通 俗一点就是一直卡在调用函数那里),直到有数据可读。当你去写一个阻塞的文件描述符时,如果在该文件描述符上没有空间(通常是缓冲区)可写,那么它会一直 阻塞,直到有空间可写。以上的读和写我们统一指在某个文件描述符进行的操作,不单单指真正的读数据,写数据,还包括接收连接accept(),发起连接 connect()等操作...</p>
<p>非阻塞IO:当你去读写一个非阻塞的文件描述符时,不管可不可以读写,它都会立即返回,返回成功说明读写操作完成了,返回失败会设置相应errno状态码,根据这个errno可以进一步执行其他处理。它不会像阻塞IO那样,卡在那里不动!!!</p>
<p><strong>二.几种IO模型的触发方式                          </strong></p>
<p> select(),poll()模型都是水平触发模式,信号驱动IO是边缘触发模式,epoll()模型即支持水平触发,也支持边缘触发,默认是水平触发。</p>
<p>这里我们要探讨epoll()的水平触发和边缘触发,以及阻塞IO和非阻塞IO对它们的影响!!!下面称水平触发为LT,边缘触发为ET。</p>
<p>对于监听的socket文件描述符我们用sockfd代替,对于accept()返回的文件描述符(即要读写的文件描述符)用connfd代替。</p>
<p>我们来验证以下几个内容:</p>
<p>1.水平触发的非阻塞sockfd</p>
<p>2.边缘触发的非阻塞sockfd</p>
<p>3.水平触发的阻塞connfd</p>
<p>4.水平触发的非阻塞connfd</p>
<p>5.边缘触发的阻塞connfd</p>
<p>6.边缘触发的非阻塞connfd</p>
<p>以上没有验证阻塞的sockfd,因为epoll_wait()返回必定是已就绪 的连接,设不设置阻塞accept()都会立即返回。例外:UNP里面有个例子,在BSD上,使用select()模型。设置阻塞的监听sockfd时, 当客户端发起连接请求,由于服务器繁忙没有来得及accept(),此时客户端自己又断开,当服务器到达accept()时,会出现阻塞。本机测试 epoll()模型没有出现这种情况,我们就暂且忽略这种情况!!!</p>
<p><strong>三.验证代码                                                         </strong></p>
<p>文件名:epoll_lt_et.c</p>
<pre class="blockcode"><code>/*
*url:http://www.cnblogs.com/yuuyuu/p/5103744.html
*
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;errno.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;arpa/inet.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/epoll.h&gt;

/* 最大缓存区大小 */
#define MAX_BUFFER_SIZE 5
/* epoll最大监听数 */
#define MAX_EPOLL_EVENTS 20
/* LT模式 */
#define EPOLL_LT 0
/* ET模式 */
#define EPOLL_ET 1
/* 文件描述符设置阻塞 */
#define FD_BLOCK 0
/* 文件描述符设置非阻塞 */
#define FD_NONBLOCK 1

/* 设置文件为非阻塞 */
int set_nonblock(int fd)
{
    int old_flags &#61; fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
    return old_flags;
}

/* 注册文件描述符到epoll,并设置其事件为EPOLLIN(可读事件) */
void addfd_to_epoll(int epoll_fd, int fd, int epoll_type, int block_type)
{
    struct epoll_event ep_event;
    ep_event.data.fd &#61; fd;
    ep_event.events &#61; EPOLLIN;

    /* 如果是ET模式,设置EPOLLET */
    if (epoll_type &#61;&#61; EPOLL_ET)
        ep_event.events |&#61; EPOLLET;
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP