zoukankan      html  css  js  c++  java
  • I/O复用

    概念

    内核一旦发现进程指定的一个或者多个I/O条件就绪(也就是说输入已准备好被读取,或者描述符已能承受更多的输出),它就通知进程。这个能力称为I/O复用(I/O multiplexing)。

    使用场景

    当处理多个多个文件描述符或者监听多个socket时,必须使用I/O复用。

    如果一个服务器要同时处理TCP和UDP,一般要使用I/O复用。

    I/O模型

    阻塞式I/O模型

    非阻塞式I/O模型

    I/O复用(select和poll)

    信号驱动式I/O模型

    异步I/O模型

    什么叫数据准备好?

    数据准备分两个阶段:1、等待网络数据到达,数据被复制到内核缓冲区,即内核空间;2、把内核数据复制到用户进程缓冲区,即用户空间

    阻塞式I/O模型

    以recvfrom系统调用为例,用户调用recvfrom,然后切换到内核态,内核等待数据到来,此时有可能阻塞(如果网络数据还没到达的话)。然后网络数据到达后将内核缓冲区数据复制到用户空间,返回成功。这时候从内核态再切换到用户态,处理数据报。

    类似这种进程一直等待数据到来,从系统调用开始到它返回,整段时间是被阻塞的。成功返回后开始处理数据报。 (进程等待的时候是被挂起休眠么?还是在干嘛?

    非阻塞式I/O模型

    把一个套接字或FD设置为非阻塞,就是通知内核,当数据没准备好时,返回一个错误,而不是一直等待。 如果有数据准备好,则复制到用户空间并返回成功指示。

    常见的用法是用一个循环去不断的调用recvfrom,去查看属否有数据准备好,这种方式被称为轮询(polling)。应用进程持续轮询内核,这么做消耗大量CPU资源。所以这种模型很少见。

    I/O复用模型

    有了I/O复用,如select,poll,我们就可以调用select或者poll,阻塞在这两个系统调用上,而不是阻塞在真正的I/O系统调用上。

    我们调用select,等待fd或者socket变为可读。当select返回套接字可读这一条件时,我们再调用recvfrom把所有可读数据从内核复制到用户空间。 

    信号驱动式I/O模型

     用的非常少,项目中目前还没有见过。略。

    异步I/O模型

    Linux的AIO目前还不成熟,故不做深入。 

    同步、异步、阻塞、非阻塞

     同步和异步关注的是事件就绪时消息通知的方式。由调用者主动询问的方式是同步,由被调用方(往往是内核)主动通知调用方任务完成的方式是异步调用。

    阻塞和非阻塞关注的是接口调用后等待数据返回时的状态。被挂起无法执行其他操作的是阻塞,可以理解返回去完成其他认识的是非阻塞模型。

    select函数

    该函数让进程指示内核等待多个socket,只有在任何一个socket准备好了(可读,可写)或者等待超时后才唤醒该进程。

    函数原型如下:

    1 #include <sys/select.h>
    2 #include <sys/time.h>
    3 
    4 int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)
    返回值:就绪描述符的数目,超时返回0,出错返回-1

     函数参数介绍如下:

    (1)第一个参数maxfdp1指定待测试的描述符的个数,其值为最大待测试的fd+1。(因此把该参数命名为maxfdp1),描述字0、1、2...maxfdp1-1均将被测试。因为文件描述符是从0开始的。

    (2)中间的三个参数readset、writeset和exceptset指定我们要让内核测试读、写和异常条件的描述字。如果对某一个的条件不感兴趣,就可以把它设为空指针。struct fd_set可理解为一个字符集,可用以下四个宏进行设置:

       void FD_ZERO(fd_set *fdset);           //清空集合

              void FD_SET(int fd, fd_set *fdset);   //将一个给定的文件描述符加入集合之中

              void FD_CLR(int fd, fd_set *fdset);   //将一个给定的文件描述符从集合中删除

              int FD_ISSET(int fd, fd_set *fdset);   // 检查集合中指定的文件描述符是否可以读写 

     (3)struct timeval设定等待时间,告知内核等待所指定描述符最多多长时间,秒和微秒组成。

    struct timeval {
        long tv_sec;       //seconds
        long tv_usec;      //micro seconds    
    }

    timeval参数有三种可能:

    第一种是空指针,表示无限等待下去,此时select为阻塞模式;

    第二种为一个有效值,表示等待时间。在等待时间内描述符就绪则返回描述符,否则返回0;

    第三种是设置为0,根本不等待直接返回,这称为轮询。

  • 相关阅读:
    org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [0, 1, param1, param2]
    在Springboot中Parameter 'XXX' not found. Available parameters are [1, 0, param1, param2]问题
    Springcould学习总结
    XXl-job基于springbooot的基本配置
    Nginx反向代理简单配置
    redis哨兵机制及配置
    redis的主从复制
    jedis在Java环境操作redis
    liunx环境redis的安装
    express之cookie和session
  • 原文地址:https://www.cnblogs.com/howo/p/7956436.html
Copyright © 2011-2022 走看看