网络编程之IO复用机制(多路IO转接)之使用管道验证epoll的LT和ET07

1 阻塞与非阻塞,LT与ET概念

  • 1)我们知道,文件描述符(例如管道,套接字等等)具有阻塞与非阻塞,例如套接字,当我们使用read去读取内容时,由于套接字默认是阻塞的,所以当没有内容时,read就会阻塞,这就是read读取阻塞的根本原因。所以阻塞就是卡住,非阻塞就是不卡住,这是最简单的理解。
  • 2)而Level Triggered (LT)和Edge Triggered (ET) 两者,前者是水平出发,只要有数据就会读取。后者是边沿触发,只有电平改变才会触发,电平改变就是0变成1(上升沿)或者1变成0(下降沿)。例如服务器与客户端连接,只有客户端发消息到套接字的缓冲区了,服务器才会认为触发到满足事件,然后去读取套接字的缓冲区。否则即使你套接字还有内容,但是客户端没有发消息,服务器也不会去读取,这就是边沿触发。
  • 3)注意,ET和LT是针对于epoll的,因为select,poll是不支持这两个模型的。

2 epoll的LT和ET详解

经过上面分析后,我们可以这样理解,阻塞非阻塞是文件描述符的属性,而描述符作为read(write不需要考虑,因为我们只需要分析读即可)的参1,该属性会影响到read,也就是说,描述符的阻塞非阻塞就是read的阻塞非阻塞。借此,我们进而可以深入分析epoll的LT和ET模型。首先先记住使用epoll的总结。
2.1 epoll的LT,ET模型是否阻塞和非阻塞总结

  • 1)epoll的LT模型支持阻塞和非阻塞。
  • 2)epoll的ET模型只支持非阻塞,不支持阻塞。

2.2 针对epoll的LT模型代码
为了方便,我们使用管道来测试。注意,select,poll,epoll都是可以在文件描述符中使用,文件描述符包括管道(即管道两个读写fd),mmap映射,网络套接字这些。这些IO复用函数虽然常用在网络套接字上,但不仅仅只能在网络套接字使用select,poll,epoll,也能用在管道等文件描述符。

案例:我们创建父子进程,然后父进程读,子进程写。子进程每次往管道写10个字节后睡眠5s,等待父进程读。父进程读,但是每次读5个,也就是说,读完5个后(睡眠1s让现象明显),管道中还有数据,若仍会触发epoll返回,去读取管道剩余的数据,就证明epoll默认是LT,LT模型是只有还有数据,我就会去读。
并且实际该例子也证明了epoll的LT模型是支持阻塞的。因为管道两个读写描述符默认就是阻塞的,程序没问题就表示支持。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <errno.h>
#include <unistd.h>

#define MAXLINE 10

int main(int argc, char *argv[])
{
    int efd, i;
    int pfd[2];
    pid_t pid;
    char buf[MAXLINE], ch = 'a';

    pipe(pfd);
    pid = fork();

    if (pid == 0) {//子进程写
        close(pfd[0]);
        while (1) {
            //aaaa\n
            for (i = 0; i < MAXLINE/2; i++)
                buf[i] = ch;
            buf[i-1] = '\n';
            ch++;
            //bbbb\n
            for (; i < MAXLINE; i++)
                buf[i] = ch;
            buf[i-1] = '\n';
            ch++;
            //aaaa\nbbbb\n
            write(pfd[1], buf, sizeof(buf));
            sleep(5);
        }
        close(pfd[1]);

    } else if (pid > 0) {//父进程读
        struct epoll_event event;
        struct epoll_event resevent[10];        //epoll_wait就绪返回event
        int res, len;

        close(pfd[1]);
        efd = epoll_create(10);

        //event.events = EPOLLIN | EPOLLET;     // ET 边沿触发
        event.events = EPOLLIN;                 // LT 水平触发 (默认)
        event.data.fd = pfd[0];
        epoll_ctl(efd, EPOLL_CTL_ADD, pfd[0], &event);

        while (1) {
            res = epoll_wait(efd, resevent, 10, -1);
            //printf("res %d\n", res);
            if (resevent[0].data.fd == pfd[0]) {
                len = read(pfd[0], buf, MAXLINE/2);
                write(STDOUT_FILENO, buf, len);
                sleep(1);
            }
        }

        close(pfd[0]);
        close(efd);

    } else {
        perror("fork");
        exit(-1);
    }

    return 0;
}


结果:
1)首先父进程会先读取5个。然后因为是LT模型,所以会继续触发epoll返回,读取剩余的5个字节。
在这里插入图片描述
在这里插入图片描述

2)然后子进程睡5s后,继续写10个字节。父进程不断重复第一步读取。
在这里插入图片描述
所以,程序正常按照猜想执行,说明epoll的默认模型是LT,并且LT模型是支持阻塞的。关于LT支持非阻塞的案例这里不举例了,可以通过fcntl这个函数设置非阻塞测试,但是个人觉得没啥必要。我们只需要知道epoll的LT和ET即可。并且这个案例只是为了让大家理解epoll的这两种
模型,实际项目很少用到。

2.3 测试epoll的ET模型代码(项目中绝不允许使用,这里只是测试,看第四小点解释)

将上面代码的注释行改成ET边沿触发即可。
//event.events = EPOLLIN | EPOLLET;     // ET 边沿触发

1)首先,子进程写了10个字节,然后父进程读取5个字节后,由于是ET模型,所以剩余的数据并不会被读取,只能等待下一次子进程写时才会触发。
在这里插入图片描述
2)接着,5s后子进程又发送10个字节,父进程将管道剩余的5字节读取即bbbb,但是本次的10个字节并未读取。
在这里插入图片描述
3)也就是说,子进程每隔5s写一次,父进程就会读一次,只有子进程写了,父进程才会去读。即使当管道还有剩余的数据,epoll也不会返回,让父进程去读。

4)看到这里,有人会问,这不是ET的阻塞模型吗?这程序不是可以运行吗,我们开始解释:我们使用的是read,因为本程序子进程不断写保证管道有数据,所以read不会阻塞,只会在epoll_wait函数阻塞。但是很多时候read并不会直接使用,很多公司会将read封装成readn,readn的作用是只有读取到一定字节数才会返回,封装阻塞。那么当readn阻塞了,客户端再发送信息,而由于程序阻塞在readn导致epoll_wait无法返回,那么程序就卡死了,无法进行任何处理。所以这里证明epoll的ET模式不支持阻塞(注意管道的文件描述符默认是阻塞)。

3 总结epoll的LT和ET

  • 1)epoll的LT模型支持阻塞和非阻塞。
  • 2)epoll的ET模型只支持非阻塞,不支持阻塞(看2.3的第4点)。
  • 3)select,poll,epoll这些IO复用函数可以用在管道,mmap映射,套接字等文件描述符的场合。

好了,本篇就是我们想要讲述的epoll的LT和ET模型,说难不难,说简单也不易,多看几篇就熟。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值