• 认识epoll


    linux下的epoll(7)函数,其有着良好的就绪事件通知机制。Epoll 是被linux2.6开始引进的,但是不被其他的类UNIX系统支持,它提供了一种类似select或poll函数的机制:
    a. Select(2)只能够同时管理FD_SETSIZE(默认为1024)数目的文件描述符,并且必须遍历所有的描述符来检查就绪的描述符。
    b. poll(2)没有固定的描述符上限这一限制,但是每次必须遍历所有的描述符来检查就绪的描述符,这个过程的时间复杂度为O(n)。
    epoll没有select这样对文件描述符上限的限制,也不会像select/poll那样进行线性的遍历。因此epoll处理大并发连接有着更高的性能。

    我们从select那里仅仅知道了,有I/O事件发生了,但却并不知道是那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。
    但是使用select,我们有O(n)的无差别轮询复杂度,同时处理的流越多,每一次无差别轮询时间就越长。
    epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll只会把哪个流发生了怎样的I/O事件通知我们(时间复杂度降低到了O(1))。此时我们对这些流的操作都是有意义的。


    Epoll相关操作函数介绍:
    1. epoll_create(2) or epoll_create1(2)(有着不同的参数值)用来创建epoll实例。
    /usr/include/sys/epoll.h
    extern int epoll_create (int __size) ;
    RETURN:>0, 成功;-1, 出错
    函数描述:
    (1) epoll_create返回的是一个文件描述符,也就是说epoll是以特殊文件的方式体现给用户
    (2) __size提示操作系统,用户可能要使用多少个文件描述符,该参数已经废弃,填写一个大于0的正整数

    2. epoll_ctl(2)用来增加或移除被epoll所监听的文件描述符。

    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    RETURN:0,成功;-1,出错

    函数描述:
    (1) epfd为epoll_create创建的epoll描述符
    (2) epoll_ctl函数对epoll进行op类型的操作,op选项为
    EPOLL_CTL_ADD,对fd描述符注册event事件
    EPOLL_CTL_MOD,对fd描述符的event事件进行修改
    EPOLL_CTL_DEL,删除已注册的event事件

    3. epoll_wait(2)用来等待发生在监听描述符上的事件。它会一直阻塞直到事件发生。
    #include

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

    RETURN:>0,发生事件个数;=0,时间到;-1,出错

    函数描述:
    epoll_wait与select函数类似,同步地等待事件发生
    (1) epfd,标识epoll的文件描述符
    (2) events,指向传入操作系统的一个epoll_event数组
    (3) maxevents,表示传入数组的大小,必须大于0
    当有事件发生,Linux会填写events结构,返回给应用程序。由于epoll_wait同步等待,有可能被信号中断,返回EINTR错误.
    这里有一个比较重要的问题:从epoll_wait返回的events中,该如何知道是哪个描述符上的事件:在注册epoll事件的时候,一定要填写epoll_data,否则我们将分不清触发的是哪个描述符上的事件。
    Epoll的两种模式:
    1. 水平触发(LT):使用此种模式,当数据可读的时候,epoll_wait()将会一直返回就绪事件。如果你没有处理完全部数据,并且再次在该 epoll实例上调用epoll_wait()才监听描述符的时候,它将会再次返回就绪事件,因为有数据可读。LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.。
    2. 边缘触发(ET):使用此种模式,只能获取一次就绪通知,如果没有处理完全部数据,并且再次调用epoll_wait()的时候,它将会阻塞,因为就绪事件已经释放出来了。ET只支持非阻塞socket。
    ET的效能更高,但是对程序员的要求也更高。在ET模式下,我们必须一次干净而彻底地处理完所有事件。
    传递给epoll_ctl(2)的Epoll事件结构体如下所示:

    typedef union epoll_data
    {
    void*ptr;
    intfd;
    __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的事件类型:
    – EPOLLIN,读事件
    – EPOLLOUT,写事件
    – EPOLLPRI,带外数据,与select的异常事件集合对应
    – EPOLLRDHUP,2.6.17 版本内核中增加了 EPOLLRDHUP 事件,代表对端断开连接(参见EPOLL事件之EPOLLRDHUP)
    – EPOLLERR,错误事件
    – EPOLLET,设置事件为边沿触发
    – EPOLLONESHOT,只触发一次,事件自动被删除
    一个文件描述符在一个epoll实例上只能注册一次,一个描述符在同一个epoll实例上注册多次,会产生EEXIST的错误。
    同样,删除epoll的事件,只需描述符就够了
    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);

    引用:

    epoll实例

    epoll 或者 kqueue 的原理是什么?

  • 相关阅读:
    【Unity游戏开发】Android6.0以上的动态权限申请问题
    【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案
    【Unity游戏开发】你真的了解UGUI中的IPointerClickHandler吗?
    【Unity游戏开发】记一次解决 LuaFunction has been disposed 的bug的过程
    【年终总结】马三北漂记之8102年总结
    【小白学Lua】之Lua变长参数和unpack函数
    【计算机图形学】计算机图形学中的坐标系统
    【Unity游戏开发】tolua之wrap文件的原理与使用
    【游戏开发】基于VS2017的OpenGL开发环境搭建
    【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher
  • 原文地址:https://www.cnblogs.com/lijingcheng/p/4454894.html
Copyright © 2020-2023  润新知