• 仔细体会 epoll中的et lt模式


    网上很多关于EPOLL的介绍,或者翻译man手册,或者找一些国外的文章,还有一些很好得心得分享。但是看完总有一种模糊的感觉,尤其是关于 ET LT 两种模式,今天自己做一些例子仔细体会下。

    一:概念

      边沿触发(edge triggered),就是在事务的两个状态交替的边沿触发,对socket来讲就是的新的数据来的时候触发,如果是上一次的数据,你没有收完 则不会再次提醒。除非有新的数据到来。

      电平触发(levle triggered),所谓电平触发只要是事务的某一状态出现就触发,对sockets来讲就是只有内核缓冲区中有数据,就会触发。而不管这数据是你上次没收完,还是新来数据。

      (以上摘自互联网)

      理解:上面提到的状态及交替,以socket接收到新的数据为分割,如果接到了新的数据,则认为交替了,没有收到新数据则认为是上一个状态未结束。

      

      代码场景:

    •    1:ET模式,得到可读事件,但是不去read数据,看epoll_wait以后是否有事件提醒。

        2:LT模式,得到可读事件,但是不去read数据,看epoll_wait以后是否有事件提醒。

    •  1:ET模式,没有及时读取数据,再次有新数据到来,能不能继续读取上次的数据。

      

      验证结果:ET模式中,接收到新数据,给数据提醒,无论读不读数据,读取多少,都只提醒一次。如果没有及时读取,则下次有新数据到来,则读取上次数据。

             LT模式中,接收到新数据,给数据提醒,只要不读完数据,一直提醒。

    二:如何处理ET模式场景

      解决此问题有两种方法:
      1.采用非阻塞函数,将数据收完后,再次调用epoll_wait(),对应epoll man手册的描述为

        i with non-blocking file descriptors

        ii by going to wait for an event only after read(2) or write(2) return EAGAIN or EWOULDBLOCK

      2.在接收数据后,不管有没有收完,都调用 epoll_ctl() with EPOLL_CTL_MOD,这样相当于重新设置事件,就可以收到数据。

      (以上摘自互联网)

      理解:如果只提醒一次,那我们就应该在用户态的代码中,"尽量完整" 并且 "尽量减少IO操作中CPU的等待" 得完成内核缓冲区的数据的读取。所以方法1中,第一步置为非阻塞,第二步中的"EAGAIN or EWOULDBLOCK"要做处理,但是没必要非等到返回这两个东西。

      附代码片段:

    conn->recv_ready=1;
        do{
            for(;;){
                if(conn->recv_ready==0){
                    break;
                }
                printf("recv starting ......
    ");
                ret=read(conn->fd,buffer,len);
                if(ret>0){
                    if(ret<(ssize_t)len){
                        conn->recv_ready=0;
                    }
                    buffer+=ret;
                    conn->recv_bytes+=(ssize_t)ret;
                }
    
                if(ret==0){
                    printf("recv done......
    ");
                    return;
                }
    
                if(ret<0){
                    if(errno==EINTR){
                        printf("recv on sd %d not ready eintr
    ",conn->fd);
                        continue;
                    }else if(errno==EAGAIN||errno==EWOULDBLOCK){
                        printf("recv on sd %d not ready eagain
    ",conn->fd);
                        conn->recv_ready=0;
                        return;
                    }else{
                        printf("recv on sd %d error
    ",conn->fd);
                        conn->recv_ready = 0;
                        return;
                    }
                }
            }
        }while(conn->recv_ready);
  • 相关阅读:
    数据流图
    数据库设计
    多媒体基础知识
    面向对象程序设计
    UML建模
    warning: integer overflow in expression [Woverflow]
    unmatched/skipped datagrams
    MFC
    D3DWindower
    cheatengine
  • 原文地址:https://www.cnblogs.com/claresun/p/3687104.html
Copyright © 2020-2023  润新知