epoll event model

Event Model

EPOLL there are two different models:

Edge Triggered (ET) edge-triggered data only until the arrival of the trigger, regardless of whether there is data in the cache.

Level Triggered (LT) level trigger as long as the data will be triggered.

Consider the following steps:

  1. We have to assume that a read data from the pipe file descriptor (RFD) was added to the epoll descriptor.
  2. The other end of the pipe 2KB of data written
  3. Call epoll_wait, and it will return RFD, indicating that it is ready to read operation
  4. 1KB of data read
  5. Call epoll_wait ......

In this process, there are two modes of operation:

ET mode

ET mode that is Edge Triggered mode.

If we add step 1 to RFD epoll descriptor when used EPOLLET flag, then after a fifth step will likely hang epoll_wait, because there is remaining data in the input buffer file, and data issued by the end still waiting for a feedback has been issued for the information of the data. Only in the file handle to monitor the occurrence of an event when ET operating mode will report the event. Therefore, in step 5, when the caller may abandon the wait is still present in the file input remaining data in the buffer. epoll work when ET mode, you must use non-blocking sockets, in order to avoid blocking a file handle to read / write blocking file descriptors to handle multiple tasks starve to death. Preferably in the following manner ET mode epoll call interface will be described later to avoid possible defects.

1) Based on the non-blocking file handle

2) only when read or write return EAGAIN (non-blocking reads, temporarily no data) need to suspend, wait. This is not to say that every time you need to read the read cycle, generates a read until EAGAIN only believe that this event completes, when read returns the read data length is less than the length of the requested data, we can determine at this time buffer has no data, it can be supposed that it read event has been processed.

LT mode

LT model that is Level Triggered mode.

And ET modes a to invoke LT epoll interface when it is equivalent to a faster poll, whether or not the latter data is used.

LT (level triggered): LT is the default operating mode, and supports both block and no-block socket. In this approach, the kernel tells you a file descriptor is ready, and then you can fd be ready for the IO operation. If you do not make any operation, the kernel will continue to inform you, therefore, this model program are less likely to point out the error. The traditional select / poll are representative of this model.

ET (edge-triggered): ET is a high-speed mode, only supports the no-block socket. In this mode, when the descriptor is ready never becomes ready, you tell the kernel through epoll. It will then assume you know the file descriptor is ready, and will not send more readiness notification for that file descriptor. Note that if you have not made this fd IO operations (which causes it to become again not ready), the kernel will not send more notifications (only once).

Example one:

Based pipeline epoll ET trigger mode

 

#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) {
            for (i = 0; i < MAXLINE/2; i++)
                buf[i] = ch;
            buf[i-1] = '\n';
            ch++;

            for (; i < MAXLINE; i++)
                buf[i] = ch;
            buf[i-1] = '\n';
            ch++;

            write(pfd[1], buf, sizeof(buf));
            sleep(2);
        }
        close(pfd[1]);
    } else if (pid > 0) {
        struct epoll_event event;
        struct epoll_event resevent[10];
        int res, len;
        close(pfd[1]);

        efd = epoll_create(10);
        /* event.events = EPOLLIN; */
        event.events = EPOLLIN | EPOLLET;        /*ET edge trigger, the trigger level is the default * / 
        Event .data.fd PFD = [ 0 ]; 
    epoll_ctl (EFD, EPOLL_CTL_ADD, PFD [ 0 ], & Event ); 

        the while ( . 1 ) { 
            RES = epoll_wait (EFD, resevent, 10 , - . 1 ); 
            the printf ( " RES% D \ n- " , RES);
             IF (resevent [ 0 ] == .data.fd PFD [ 0 ]) { 
                len = Read (PFD [ 0 ], buf, MAXLINE / 2 );  
                Write (STDOUT_FILENO, buf, len);
            } 
        }
        close(pfd[0]);
        close(efd);
    } else {
        perror("fork");
        exit(-1);
    }
    return 0;
}

Trigger level:

operation result:

ubuntu1604 @ ubuntu: ~ / wangqinghe / linux / 20190827 $ ./et

res 1

yyyy

res 1

bbbb

res 1

cccc

res 1

dddd

res 1

eeee

res 1

ffff

^C

Example 2:

Epoll ET trigger mode based on network C / S Model

server

 

/* server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <unistd.h>

#define MAXLINE 10
#define SERV_PORT 8080

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int i, efd;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    listen(listenfd, 20);

    struct epoll_event Event ;
     struct epoll_event resevent [ 10 ];
     int RES, len; 
    efd = epoll_create ( 10 );
     Event .events = EPOLLIN | EPOLLET;         / * ET edge trigger, the trigger level is the default * / 

    printf ( " Accepting Connections ... \ n- " ); 
    cliaddr_len = the sizeof (cliaddr); 
    connfd = Accept (listenfd, ( struct the sockaddr *) & cliaddr, & cliaddr_len); 
    the printf ( " Received from AT PORT% S% D \ n- "  ,
            inet_ntop (AF_INET,&cliaddr.sin_addr, str, sizeof(str)),
            ntohs(cliaddr.sin_port));

    event.data.fd = connfd;
    epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event);

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

client

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define MAXLINE 10
#define SERV_PORT 8080

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, i;
    char ch = 'a';

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (1) {
        for (i = 0; i < MAXLINE/2; i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;

        for (; i < MAXLINE; i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;

        write(sockfd, buf, sizeof(buf));
        sleep(10);
    }
    Close(sockfd);
    return 0;
}

 

Edge Trigger:

operation result:

ubuntu1604 @ ubuntu: ~ / wangqinghe / linux / 20190827 $ ./et

res 1

yyyy

res 1

bbbb

res 1

cccc

^C

 

Three examples:

Based epoll ET network C / S model trigger mode nonblocking

server

/* server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>

#define MAXLINE 10
#define SERV_PORT 8080

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int i, efd, flag;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    listen(listenfd, 20);

    structepoll_event Event ;
     struct epoll_event resevent [ 10 ];
     int RES, len; 
    EFD = epoll_create ( 10 );
     / * event.events = EPOLLIN; * / 
    Event .events = EPOLLIN | EPOLLET;         / * the ET edge trigger, the trigger level defaults * / 

    the printf ( " Accepting Connections ... \ n- " ); 
    cliaddr_len = the sizeof (cliaddr); 
    connfd = Accept (listenfd, ( struct the sockaddr *) & cliaddr, & cliaddr_len); 
    the printf ( "received from %s at PORT %d\n",
            inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
            ntohs(cliaddr.sin_port));

    flag = fcntl(connfd, F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(connfd, F_SETFL, flag);
    event.data.fd = connfd;
    epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event);

    while (1) {
        printf("epoll_wait begin\n");
        res = epoll_wait(efd, resevent, 10, -1);
        printf("epoll_wait end res %d\n", res);

        if (resevent[0].data.fd == connfd) {
            while ((len = read(connfd, buf, MAXLINE/2)) > 0)
                write(STDOUT_FILENO, buf, len);
        }
    }
    return 0;
}

client

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define MAXLINE 10
#define SERV_PORT 8080

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, i;
    char ch = 'a';

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (1) {
        for (i = 0; i < MAXLINE/2; i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;

        for (; i < MAXLINE; i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;

        write(sockfd, buf, sizeof(buf));
        sleep(10);
    }
    Close(sockfd);
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/wanghao-boke/p/11425936.html