select、poll、epoll的区别以及epoll的两种模式(LT、ET)以及实现

引自:https://blog.csdn.net/qq_41038824/article/details/88537640

select和poll的缺点:

(1)、每轮循环都要从用户空间往内核空间拷贝数据;

(2)、内核轮询,检测每个描述符有没有就绪事件,O(n);

(3)、I/O函数返回后,遍历每个描述符找到有事件就绪的描述符,O(n);

(select、poll)和(epoll)的区别:

(1)、select、poll每次循环都需要从用户空间向内核空间传递数据;

             epoll直接在内核空间创建事件表,每个描述符只需要传递一次;

(2)、select、poll在内核中以轮询的方式检测就绪事件描述符;

             epoll在每个描述符上注册回调函数,事件就绪后执行回调函数将描述符添加到就绪队列;

(3)、select、epoll返回后,需要遍历所有文件描述符,才能找到就绪的文件描述符;

             epoll返回后,直接得到就绪描述符不需要遍历所有描述符;

epoll的两种模式:

(1)、LT模式(电平触发):描述符事件就绪后,如果用户没有处理完数据,epoll会一直提醒,直到处理完成;代码实现(epoll-LT.c

(2)、ET模式(边沿触发):高效模式。描述符事件就绪后,无论用户有没有处理完数据,epoll都只会提醒一次,所以在处理时要获取完整数据,需要循环获取所有数据;代码实现(epoll-ET.c

  1.  
    //epoll-LT.c
  2.  
    //I/O复用:epoll() LT模式
  3.  
    //LT模式:描述符时间就绪后,如果用户没有处理完数据,epoll会反复提醒,直到处理完成
  4.  
     
  5.  
    #define _GNU_SOURCE
  6.  
     
  7.  
    #include <stdio.h>
  8.  
    #include <unistd.h>
  9.  
    #include <stdlib.h>
  10.  
    #include <string.h>
  11.  
    #include <assert.h>
  12.  
    #include <sys/socket.h>
  13.  
    #include <netinet/in.h>
  14.  
    #include <arpa/inet.h>
  15.  
    #include <pthread.h>
  16.  
    #include <sys/epoll.h>
  17.  
     
  18.  
    #define MAXFD 10
  19.  
    int create_socket();
  20.  
    void epoll_add(int epfd,int fd)
  21.  
    {
  22.  
    struct epoll_event ev;
  23.  
    ev.events = EPOLLIN; //LT模式
  24.  
    ev.data.fd = fd;
  25.  
     
  26.  
    if( epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev) == -1 )
  27.  
    {
  28.  
    perror("epoll_ctl error");
  29.  
    }
  30.  
    }
  31.  
     
  32.  
    void epoll_del(int epfd,int fd)
  33.  
    {
  34.  
    if( epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL) == -1 )
  35.  
    {
  36.  
    perror("epoll del erreo");
  37.  
    }
  38.  
    }
  39.  
    int main()
  40.  
    {
  41.  
    int sockfd = create_socket();
  42.  
    assert(sockfd != -1);
  43.  
     
  44.  
    int epfd = epoll_create(MAXFD);
  45.  
    assert(epfd != -1);
  46.  
     
  47.  
    epoll_add(epfd,sockfd);
  48.  
     
  49.  
    struct epoll_event events[MAXFD];
  50.  
    while (1)
  51.  
    {
  52.  
    int n = epoll_wait(epfd,events,MAXFD,5000);
  53.  
    if( n == -1 )
  54.  
    {
  55.  
    perror("epoll error");
  56.  
    }
  57.  
    else if(n == 0)
  58.  
    {
  59.  
    printf("time out ");
  60.  
    }
  61.  
    else
  62.  
    {
  63.  
    int i = 0;
  64.  
    for(;i<n;i++)
  65.  
    {
  66.  
    if(events[i].events & EPOLLIN)
  67.  
    {
  68.  
    if( events[i].data.fd == sockfd )
  69.  
    {
  70.  
    struct sockaddr_in caddr;
  71.  
    int len = sizeof(caddr);
  72.  
    int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
  73.  
    if ( c < 0 )
  74.  
    {
  75.  
    continue;
  76.  
    }
  77.  
    epoll_add(epfd,c);
  78.  
    printf("accept = %d ",c);
  79.  
    }
  80.  
    else
  81.  
    {
  82.  
    char buff[128] = {0};
  83.  
    int num = recv(events[i].data.fd,buff,1,0);
  84.  
    if( num <= 0)
  85.  
    {
  86.  
    epoll_del(epfd,events[i].data.fd);
  87.  
    close(events[i].data.fd);
  88.  
    printf("one client over ");
  89.  
     
  90.  
    }
  91.  
    else
  92.  
    {
  93.  
    printf("recv(%d):%s ",events[i].data.fd,buff);
  94.  
    send(events[i].data.fd,"ok",2,0);
  95.  
    }
  96.  
    }
  97.  
    }
  98.  
    }
  99.  
    }
  100.  
    }
  101.  
     
  102.  
    }
  103.  
     
  104.  
    int create_socket()
  105.  
    {
  106.  
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
  107.  
    if(sockfd == -1)
  108.  
    {
  109.  
    return -1;
  110.  
    }
  111.  
     
  112.  
    struct sockaddr_in saddr;
  113.  
    memset(&saddr,0,sizeof(saddr));
  114.  
    saddr.sin_family = AF_INET;
  115.  
    saddr.sin_port = htons(6000);
  116.  
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  117.  
     
  118.  
    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
  119.  
    assert(res != -1);
  120.  
    listen(sockfd,5);
  121.  
    return sockfd;
  122.  
    }
  1.  
    //epoll-ET.c
  2.  
    //I/O复用:epoll() ET模式
  3.  
    //ET模式必须使用非阻塞模式
  4.  
     
  5.  
    #define _GNU_SOURCE
  6.  
     
  7.  
    #include <stdio.h>
  8.  
    #include <unistd.h>
  9.  
    #include <stdlib.h>
  10.  
    #include <string.h>
  11.  
    #include <assert.h>
  12.  
    #include <sys/socket.h>
  13.  
    #include <netinet/in.h>
  14.  
    #include <arpa/inet.h>
  15.  
    #include <pthread.h>
  16.  
    #include <sys/epoll.h>
  17.  
    #include <fcntl.h>
  18.  
     
  19.  
    #define MAXFD 10
  20.  
    int create_socket();
  21.  
    void setnonblock(int fd)
  22.  
    {
  23.  
    int oldflg = fcntl(fd,F_GETFL); //fcntl()可以设置非阻塞
  24.  
    int newflg = oldflg | O_NONBLOCK;
  25.  
     
  26.  
    if(fcntl(fd,F_SETFL,newflg) == -1)
  27.  
    {
  28.  
    perror("fcntl error ");
  29.  
    }
  30.  
    }
  31.  
    void epoll_add(int epfd,int fd)
  32.  
    {
  33.  
    struct epoll_event ev;
  34.  
    ev.events = EPOLLIN | EPOLLET; //ET模式
  35.  
    ev.data.fd = fd;
  36.  
     
  37.  
    setnonblock(fd);
  38.  
     
  39.  
    if( epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev) == -1 )
  40.  
    {
  41.  
    perror("epoll_ctl error");
  42.  
    }
  43.  
    }
  44.  
     
  45.  
    void epoll_del(int epfd,int fd)
  46.  
    {
  47.  
    if( epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL) == -1 )
  48.  
    {
  49.  
    perror("epoll del erreo");
  50.  
    }
  51.  
    }
  52.  
    int main()
  53.  
    {
  54.  
    int sockfd = create_socket();
  55.  
    assert(sockfd != -1);
  56.  
     
  57.  
    int epfd = epoll_create(MAXFD);
  58.  
    assert(epfd != -1);
  59.  
     
  60.  
    epoll_add(epfd,sockfd);
  61.  
     
  62.  
    struct epoll_event events[MAXFD];
  63.  
    while (1)
  64.  
    {
  65.  
    int n = epoll_wait(epfd,events,MAXFD,5000);
  66.  
    if( n == -1 )
  67.  
    {
  68.  
    perror("epoll error");
  69.  
    }
  70.  
    else if(n == 0)
  71.  
    {
  72.  
    printf("time out ");
  73.  
    }
  74.  
    else
  75.  
    {
  76.  
    int i = 0;
  77.  
    for(;i<n;i++)
  78.  
    {
  79.  
    int fd = events[i].data.fd;
  80.  
    if(events[i].events & EPOLLIN)
  81.  
    {
  82.  
    if( fd == sockfd )
  83.  
    {
  84.  
    struct sockaddr_in caddr;
  85.  
    int len = sizeof(caddr);
  86.  
    int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
  87.  
    if ( c < 0 )
  88.  
    {
  89.  
    continue;
  90.  
    }
  91.  
    epoll_add(epfd,c);
  92.  
    printf("accept = %d ",c);
  93.  
    }
  94.  
    else
  95.  
    {
  96.  
    while(1)
  97.  
    {
  98.  
    char buff[128] = {0};
  99.  
    int num = recv(fd,buff,1,0);
  100.  
    if( num == -1 )
  101.  
    {
  102.  
    send(fd,"ok",2,0);
  103.  
    break;
  104.  
    }
  105.  
    else if( num == 0 )
  106.  
    {
  107.  
    epoll_del(epfd,fd);
  108.  
    close(fd);
  109.  
    printf("one client over ");
  110.  
    break;
  111.  
    }
  112.  
    else
  113.  
    {
  114.  
    printf("buff(%d) = %s ",fd,buff);
  115.  
    }
  116.  
    }
  117.  
    }
  118.  
    }
  119.  
    }
  120.  
    }
  121.  
    }
  122.  
    }
  123.  
     
  124.  
    int create_socket()
  125.  
    {
  126.  
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
  127.  
    if(sockfd == -1)
  128.  
    {
  129.  
    return -1;
  130.  
    }
  131.  
     
  132.  
    struct sockaddr_in saddr;
  133.  
    memset(&saddr,0,sizeof(saddr));
  134.  
    saddr.sin_family = AF_INET;
  135.  
    saddr.sin_port = htons(6000);
  136.  
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  137.  
     
  138.  
    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
  139.  
    assert(res != -1);
  140.  
    listen(sockfd,5);
  141.  
     
  142.  
    return sockfd;
  143.  
    }

select、poll、epoll的区别以及epoll的两种模式(LT、ET)以及实现

原文地址:https://www.cnblogs.com/lyp1010/p/13841054.html