设为首页 加入收藏

TOP

IO多路复用(一)
2023-07-23 13:40:42 】 浏览:61
Tags:路复用

1.IO多路复用的概念

2.为什么出现IO多路复用

  • 服务器需要维护N多个与客户端之间的socketfd;并且在receive之前需要知道数据知否出现---》组件IO多路复用技术出现---》解决检测服务器端N多个fd的状态

    • Tcp是有连接的,Udp是无连接---》上述情况出现在Tcp连接情况
  • IO多路复用的三种方案:select/poll/epoll

    • select(fds+1, rds, wds, timeout)
    • poll(fds, nfd, timeout)
    • epoll
      • epoll_create(size/flags)--》创建根节点---》epoll实例
      • epoll_ctl(fd, op, events)---》挂载fd节点
      • epoll_wait(fd, events, maxevents, timeout)---》检测
  • Tcp建立连接---》需要的fds放入IO多路复用中管理---》检测fd缓存状态---》receive

    • receive(fd,buff,sizeof(buff),0)

3.IO多路复用区别特点

select poll epoll
性能 随IO处理数增加,性能逐渐下降;并且连接数有限制 随IO处理数增加,性能逐渐下降 随IO处理数增加,性能基本上不会下降
连接数 最大连接数1024;处理1024以上则需要修改宏FD_SETSIZE,重新编译 无限制 无限制
数据结构 不确定,有数组的可能,但是为线性结构 不确定,有链表的可能,但是为线性结构 红黑树,队列
处理方式 线性轮询 线性轮询 回调callback
内存拷贝 所有fds从用户空间和内核空间来回拷贝** 所有fds从用户空间和内核空间来回拷贝 epoll_wait()只需要从就绪队列上拷贝由内核空间到用户空间
使用复杂度
时间复杂度 O(n) O(n) O()
  • select/poll
    • 拷贝fds--》从用户空间至内核
    • for(;;)进行遍历判断
      • select:进行分类rds,wds,eds
      • poll:pollfd维护自身状态
    • 从内核拷贝至用户空间
  • epoll
    • epoll_create--->创建一个根节点
    • epoll_ctl---》挂载节点
    • epoll_wait---》从内核到用户只拷贝满足条件的节点,从就绪队列中拷贝
  • 在哪些场景下 select比epoll更合适?
    • IO数量不多,且使用多线程多进程的情况使用select比epoll更合适
      • epoll使用红黑树,必须需要加锁,消耗的资源更多

红黑树:

? 等待补充链接

3.IO多路复用源码

  • select:kern_select---》core_sys_select---》do_select---linux-6.0.2\fs\select.c

    • static int kern_select(int n, fd_set __user *inp, fd_set __user *outp,fd_set __user *exp, struct __kernel_old_timeva l __user *tvp){
      	struct timespec64 end_time, *to = NULL;
      	struct __kernel_old_timeva l tv;
      	int ret;
      	if (tvp) {
              //copy_from_user从用户空间拷贝fds
      		if (copy_from_user(&tv, tvp, sizeof(tv)))
      			return -EFAULT;
      		to = &end_time;
      		if (poll_select_set_timeout(to,
      				tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
      				(tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
      			return -EINVAL;
      	}
          //调用select--》core_sys_select
      	ret = core_sys_select(n, inp, outp, exp, to);
      	return poll_select_finish(&end_time, tvp, PT_TIMeva l, ret);
      }
      
    • int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
      			   fd_set __user *exp, struct timespec64 *end_time)
      {
      	......
          //加读锁,读取文件数量
          rcu_read_lock();
      	fdt = files_fdtable(current->files);
      	max_fds = fdt->max_fds;
      	rcu_read_unlock();
          ......
      	//select底层处理---》do_select
      	ret = do_select(n, &fds, end_time);
      
      	if (ret < 0)
      		goto out;
      	if (!ret) {
      		ret = -ERESTARTNOHAND;
      		if (signal_pending(current))
      			goto out;
      		ret = 0;
      	}
      	......
      out_nofds:
      	return ret;
      }
      
    • static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
      {
          .....
          //读锁,读取文件数量
      	rcu_read_lock();
      	retval = max_select_fd(n, fds);
      	rcu_read_unlock();
      	.....
          //通过循环遍历,主要流程流程
      	for (;;) {
      		unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
      		bool can_busy_loop = false;
      
      		inp = fds->in; outp = fds->out; exp = fds->ex;
      		rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
      
      		for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
      			unsigned long in, out, ex, all_bits, bit = 1, j;
      			unsigned long res_in = 0, res_out = 0, res_ex = 0;
      			__poll_t mask;
      
      			in = *inp++; out = *outp++; ex = *exp++;
      			all_bits = in | out | ex;
      			if (all_bits == 0) {
      				i += BITS_PER_LONG;
      				continue;
      			}
      
      			for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit &
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Centos7配置webrtc-streamer环境 下一篇SRE:如何提高报警有效性?

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目