当前位置:   article > 正文

网络: 多路复用

网络: 多路复用
  • 概念: 多路复用: 一种通信传输技术, 使多条数据流或信号共享同一传输介质
  • 网络中的多路复用: 一个进程能够同时监控多个文件描述符的IO事件

特点

select

缺点

  • 设置关注文件描述符的结构是位图, 有数量限制1024
  • fdset无法复用, 每次循环必须重新创建
  • 频繁的用户态和内核态拷贝, 性能开销大
  • 检查关注的fd, 已就绪的fd都需要遍历. O(n)轮询的时间复杂度

poll

优点

  • pollfd结构包含了要监视的event和发生的event,只需要被初始化一次
  • 采用结构体, 解决select文件描述符1024的个数限制

缺点

  • 仍然存在频繁的用户态和内核态拷贝, 性能开销大
  • 检查关注的fd, 已就绪的fd仍需要遍历. O(n)轮询的时间复杂度

epoll

优点

  • 检查就绪的文件描述符更快(为O(1), 就绪队列结构)
  • 不用频繁的在用户态和内核态之间拷贝(红黑树 + 双链表, 会记录要关注的fd和就绪的fd). 相比于select不用老是传递之前的文件描述符

缺点

  • 内核要维护红黑树 + 双链表(更占内存)
  • 当要监听的文件描述符较少时, 其速度不一定比poll快

epoll触发机制

  • LT(水平触发): 只要底层有事件就绪且没被取走, 就会一直通知上层
  • ET(边缘触发): 只有就绪事件变化的时候, 才会通知上层(且只通知一次)

原理

select

  • 将关注的所有fd, 一次性从用户态拷贝到内核态
  • 内核态遍历每个fd, 检测是否有数据到达
  • 将所有fd状态从内核态拷贝回用户态, 并返回就绪fd个数
  • 用户态遍历所有fd, 找到已就绪的fd, 然后进行事件处理

poll

  • 将当前进程所有的为你教案描述符, 一次性从用户态拷贝到内核态
  • 在内核中快速的无差别遍历每个fd, 判断是否有数据达到
  • 将所有fd状态, 从内核态拷贝到用户态, 并返回已就绪fd个数
  • 在用户态遍历判断具体哪个fd就绪, 然后进行时间处理

epoll

  • 和select,poll类似, 但在内核维护了红黑树 + 双链表且使用回调机制减少了select的缺点

操作

  • select

头文件: <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

  1. nfds : 需要监视的最大的文件描述符值+1. (用来确定遍历范围)
  2. read : 可读文件描述符的集合
  3. write : 可写文件描述符的集合
  4. except : 异常文件描述符的集合
  5. timeout: 超时时间(若超过该时间, 还没有事件就绪就返回)
  6. NULL: 一直阻塞
  7. 0: 不阻塞

fd_set系列

  1. void FD_ZERO(fd_set *set); // 用来清除描述词组set的全部位
  2. void FD_CLR(int fd, fd_set *set); // 用来清除描述词组set中相关fd的位
  3. void FD_SET(int fd, fd_set *set); // 用来设置描述词组set中相关fd的位
  4. int FD_ISSET(int fd, fd_set *set); // 用来测试描述词组set中相关fd的位是否为真

  • poll

头文件: <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

  1. struct pollfd {
  2. int fd; //文件描述符
  3. short events; //监听事件集合
  4. short revents; //返回事件集合
  5. };
  6. nfds: fds数组的长度
  7. timeout: 超时时间

events与revents的取值

  • epoll

epoll_create

  1. 函数 : epoll_create(size_t size);
  2. 功能 : 创建一个epoll模型
  3. 返回值: 用一个数表示这个epoll
  4. 参数 : size: 文件描述符个数
  5. 注 : 但自从linux2.6.8之后,size参数是被忽略的
  6. 用完之后, 必须调用close()关闭

epoll_ctl

  1. 函数:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  2. 功能:注册要监听的事件类型
  3. epfd : epoll_create()的返回值(epoll的句柄)
  4. fd : 需要监听的fd
  5. event: 告诉内核需要监听什么事
  6. op : 用三个宏来表示
  7. EPOLL_CTL_ADD :注册新的fd到epfd中;
  8. EPOLL_CTL_MOD :修改已经注册的fd的监听事件;
  9. EPOLL_CTL_DEL :从epfd中删除一个fd;

epoll_wait

  1. int epoll_wait(int epfd,struct epoll_event * events,int maxevents, nt timeout);
  2. 功能: 收集在epoll监控的事件中已经发送的事件
  3. events :分配好的epoll_event结构体数组.
  4. maxevents: 告诉内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size.
  5. timeout : 超时时间(0会立即返回,-1是永久阻塞)
  6. 返回值:
  7. 成功 :返回对应I/O上已准备好的文件描述符数目
  8. 0 :表示已超时
  9. 小于0:表示函数失败
  10. epoll将会把发生的事件赋值到events数组中
  11. events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/562712
推荐阅读
相关标签
  

闽ICP备14008679号