• aio-epoll


    epoll是Linux高效网络的基础,比如event poll(例如nodejs),是使用libev,而libev的底层就是epoll(只不过不同的平台可能用epoll,可能用kqueue)。epoll能够高效支持百万级别的句柄监听。

    select需要轮询所有fd才能得知哪些fd有事件发生(在fd很多时,轮询就变得吃力了),而epoll有事件发生的fd被主动存放在了一个链表中(在中断处理程序中注册回调函数,回调函数会将发生事件的fd放入链表中);在每次select时都需要重新向内核复制需要监听的fd,而epoll只需要最初复制一次即可(如果是EPOLLONESHOT,则需要每次都重新监听事件)。

    epoll的接口只有3个函数:

    1 //创建一个epoll的句柄,size用来告诉内核这个监听的数目的估计值,用于预分配空间
    2 int epfd = epoll_create(intsize);       
    3 //将被监听的描述符添加到epoll句柄或从epool句柄中删除或者对监听事件进行修改。
    4 //epfd即epoll_create的返回值,op有3个可选值(EPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL),fd即需要监听的fileDescriptor,event是在fd上需要监听的事件,有7个可选值(EPOLLIND等)
    5 int epoll_ctl(int epfd, int op, int fd, struct epoll_event*event); 
    6 //等待事件触发,当超过timeout还没有事件触发时,就超时
    7 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

    epoll的数据结构如下,其中最重要的就是rdllist(List of ready file descriptors)和rbr(red black root) ,rdllist链表元素代表就绪事件,rbr红黑树上的节点代表所有注册在该epoll上的fileDescriptor,插入、更新、删除fileDescriptor时是在红黑树上操作,会很快。在epoll上注册事件后就不需要重复注册了(除非使用了EPOLLONESHOT),socket的中断处理程序中注册一个回调函数,当socket与内核缓冲区完成数据交互后就会运行中断处理程序,此时就会运行回调函数,该函数会将socket事件放入rdllist中。epoll只需要监控rdllist链表即可,当rdllist非空时就会将rdllist上的事件返回给用户区,这时我们就得到了事件及发生事件的socket(epoll_wait会返回事件地址,通过事件地址就可以得到fileDescriptor,在java的EPollPort中维护着fileDescriptor到channel的映射),然后就可以进一步处理了。

    1 struct eventpoll{
    2     ....
    3     /*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/
    4     struct rb_root  rbr;
    5     /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/
    6     struct list_head rdlist;
    7     ....
    8 };
    1 struct epitem{
    2     struct rb_node  rbn;//红黑树节点
    3     struct list_head    rdllink;//双向链表节点
    4     struct epoll_filefd  ffd;  //事件句柄信息
    5     struct eventpoll *ep;    //指向其所属的eventpoll对象
    6     struct epoll_event event; //期待发生的事件类型
    7 }

    LT, ET

    当一个socket句柄上有事件时,内核会把该句柄插入上面所说的准备就绪list链表,这时我们调用epoll_wait,会把准备就绪的socket拷贝到用户态内存,然后清空准备就绪list链表,最后,epoll_wait干了件事,就是检查这些socket,如果是LT模式(非ET模式),并且这些socket上确实有未处理的事件时,又把该句柄放回到刚刚清空的准备就绪链表了。所以,LT的句柄,只要它上面还有事件,epoll_wait每次都会返回这个句柄。(从上面这段,可以看出,LT还有个回放的过程,低效了

    java中的aio是LT模式,因为sun.nio.ch.Port中只存在以下4个事件

    1 static final short POLLIN       = 0x0001;
    2 static final short POLLOUT      = 0x0004;
    3 static final short POLLERR      = 0x0008;
    4 static final short POLLHUP      = 0x0010;

    events

    events可以是以下几个宏的集合:

    EPOLLIN:            触发该事件,表示对应的文件描述符上有可读数据。(包括对端SOCKET正常关闭);

    EPOLLOUT:         触发该事件,表示对应的文件描述符上可以写数据;

    EPOLLPRI:           表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);

    EPOLLERR:        表示对应的文件描述符发生错误;

    EPOLLHUP:        表示对应的文件描述符被挂断;

    EPOLLET:           将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

    EPOLLONESHOT:  只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。

    参考:http://www.cnblogs.com/charlesblc/p/6242479.html

      http://blog.csdn.net/yusiguyuan/article/details/15027821

  • 相关阅读:
    AC自动机(转载)
    hdu 4352 XHXJ's LIS(数位dp+状压)
    hdu 4734 F(x)(数位dp)
    hdu 3709 Balanced Number(数位dp)
    hdu 6268 Master of Subgraph(点分治+bitset)
    poj 1741 tree(点分治)
    pytorch 矩阵数据增加维度unsqueeze和降低维度squeeze
    pytorch seq2seq模型中加入teacher_forcing机制
    pytorch seq2seq模型训练测试
    python os模块判断文件是否存在,file_path获取当前文件路径
  • 原文地址:https://www.cnblogs.com/holoyong/p/7354244.html
Copyright © 2020-2023  润新知