• epoll的使用


    关于epoll

        上一篇博文提到过select的使用方法。今天说一下epoll的使用方法。epoll相对于select而言有如下几个方面的优点:

    • 对于要监听的fd的数量没有限制

    • 内核会保存需要监听的fd,无需每次都进行初始化

    • 只返回产生事件(可读取、可写等)的fd,无需遍历监听的所有fd

         使用epoll主要用进行一步阻塞的调用。其基本的步骤为

    • 首先通过epoll_create调用创建一个epoll文件描述符(epfd)

    • 通过epoll_ctl对这个描述符进行设置,具体包括:添加需要监听的文件描述符、socket描述符等;设置相关监听的类型(例如监听是否可读:EPOLLIN,)等

    • 通过epoll_wait进行事件的监听

           看一段代码示例:

           #include <sys/epoll.h>

    #include <unistd.h>

    #include <stdlib.h>

    #include <sys/types.h>

     

    int main(int argc, char* argv[])

    {

      //epoll_event用于epoll_ctl中与关联的fd进行设置,events用于epoll_wait返回可以处理的fd的信息

       struct epoll_event epollEvent, events[10];

       //监听时间设置为可读时触发

       epollEvent.events = EPOLLIN ;

       epollEvent.data.fd = 0;

       char buf[100];

      //创建epfd

       int epollFd = epoll_create(10);

       const char* errStr = "epoll_Create failed ";

      //如果创建失败,则返回

       if(epollFd < 0)

       {

           

           write(2, errStr, 20);

           exit(-1);

       }

       errStr = "epoll_ctl failed ";

     //监听标准输入, 将stdin添加至监听fd集合中

       if(-1 == epoll_ctl(epollFd, EPOLL_CTL_ADD, 0, &epollEvent))

       {

           write(2, errStr, 17);

           exit(-1);

       }

       int nfds;

       const char* splitLine = "---------- ";

       while(1)

       {

         //当stdin可读时,epoll_wait返回,超时时间设置为一直阻塞,知道有可用的fd时返回

           nfds = epoll_wait(epollFd, events, 10, -1);

           int i;

          //对可用的fd进行处理

           for(i = 0; i < nfds; ++i)

           {

               int readCount = read(events[i].data.fd, buf, 5);

               if(0 == readCount)

               {

                   close(epollFd);

                   exit(0);

               }

               write(1, buf, readCount);

               write(1, splitLine, 11);

           }

           //epoll_ctl(epollFd, EPOLL_CTL_MOD, 0, &epollEvent);

       }

       close(epollFd);

       return 0;

    }

    辅助的python脚本

    #!/usr/bin/env python

    #coding:utf-8


    import time


    output_str = "hello world"


    for i in range(0, 5):

       print output_str

       time.sleep(2)

    gcc -o test_epoll test_epoll.c -g -Wall

    python cat_py.py | ./test_epoll

    下面具体讲解一下每个函数的用法,详情请参考linux的官方文档(http://man7.org/linux/man-pages/man7/epoll.7.html),

         头文件#include <sys/epoll.h>

         函数原型:int epoll_create(int size);

    size为需要监听的文件描述的数量,内核用该值去分分配相应的空间,但是自从内核2.6.8之后,使用动态的空间分配方式,size的取值已经被忽略,但是必须设置为大于0的数值。该函数的返回值为epoll的文件描述符,该描述符将用于后续的epoll_ctl和epoll_wait等的操作。

    函数原型: int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    其中epfd为epoll_create的返回值,就是epoll的文件描述符,所有需要监听的fd都需要与epfd进行关联。

    op为EPOLL_CTL_ADD、EPOLL_CTL_MOD和EPOLL_CTL_DEL三者之一EPOLL_CTL_ADD用于添加需要监听的文件描述符,即参数中的fd,将fd添加到需要监听的文件描述符集合中。EPOLL_CTL_MOD用于改变与fd进行关联的event。EPOLL_CTL_DEL用于将fd从监听的集合中删除。

    对于epoll_event要做稍微详细的介绍:

    typedef union epoll_data {

       void        *ptr;

       int          fd;

       uint32_t     u32;

       uint64_t     u64;

    } epoll_data_t;


    struct epoll_event {

          uint32_t     events;      /* Epoll events */

          epoll_data_t data;        /* User data variable */

    };

    此处主要设置epoll_event中的events,events的取值主要由EPOLLIN、EPOLLOUT、EPOLLRDHUP和EPOLLET等具体参考http://man7.org/linux/man-pages/man2/epoll_ctl.2.html  

    EPOLLIN监听fd是否可读,EPOLLOUT监听fd是否可写。需要着重指出的是:epoll默认的事件触发机制是水平触发,因此如果使用EPOLLET则设置为边缘触发,对于边缘触发,在一次触发以后(epoll_wait返回处理后)要需要再次调用epoll_ctl使用EPOLL_CTL_MOD进行事件关联。否则如果本次处理不完全,例如有2k的字节可读,而只读取了1k,如果不再次设置,则再次调用epoll_wait后不会返回,因而可能会造成数据的丢失。epoll_data与fd想关联,保存着fd相关的信息。

    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

    epfd为epoll的fd,events为返回的对应fd的event的数组,maxevents为一次可以处理的fd的最大数量,通常设置为需要监听的fd的数量,timeout为超时返回的秒数。如果为0,则立即返回,如果为-1则一直阻塞,直到有需要处理的fd则返回。epoll_wait的返回值为目前可用的fd的数量。另外,如果发生错误则返回-1并设置errno。









  • 相关阅读:
    转------深入理解--Java按值传递和按引用传递
    排序算法 -------未完待续
    eclipse智能提示报错(to avoid the message, disable the...)
    关于hashcode 和 equals 的内容总结
    随笔 软件设计师 -----------考后总结
    wpf 中用 C# 代码创建 PropertyPath ,以对间接目标进行 Storyboard 动画.
    AvaloniaUI体验
    wpf 通过为DataGrid所绑定的数据源类型的属性设置Attribute改变DataGrid自动生成列的顺序
    wpf 在不同DPI下如何在DrawingVisual中画出清晰的图形
    基于libcurl实现REST风格http/https的get和post
  • 原文地址:https://www.cnblogs.com/xiangyu01/p/3353580.html
Copyright © 2020-2023  润新知