多路转接select1

高级IO

通常情况下所有的 IO 都可以分为两步来完成, 第一步等待, 第二步数据搬迁, 为了提高 IO 效率通常所运用的方法就是减少等待的时间

举个钓鱼的例子

现在有五个人张三, 李四, 王五, 赵六, 钱七. 它们五个人来到湖边来钓鱼. 而它们五个人的钓鱼方各不相同.
张三钓鱼方法:
往鱼钩上挂上鱼饵, 然后一动不动地盯着鱼饵, 不管有任何人来叫张三, 张三谁都不理, 唯一关注的就是是否有鱼上钩, 于是就一直盯着鱼漂, 只要鱼漂有动静, 就说明有鱼上钩, 于是将上钩的鱼拉上来.
李四钓鱼方法:
将鱼饵往鱼钩上一挂, 将鱼钩和鱼饵全部扔到河里, 然后他一边钓鱼, 一边玩手机, 然后问一下张三钓了多少鱼, 但是张三一直关注的是自己的鱼漂是否有动静, 它根本就不理李四, 玩一会儿手机定期看一下是否有鱼上钩.
王五钓鱼方法:
王五比较聪明, 他看到张三和李四两个人一个在那里傻傻地盯着鱼漂, 一个像话唠一样一直问着旁边的人,于是他相处了一个办法, 他往挂鱼饵的那个地方挂一个铃铛, 只要铃铛一响, 他便将鱼从水里拉出来. 如果铃铛没有响, 自己该干什么就干什么.
赵六钓鱼方法:
赵六相比前面的张三, 李四, 王五来说比较富裕, 他来的时候拿了好多个鱼竿, 于是他将所有的鱼竿往岸边一插, 并且对这些鱼竿进行编号, 然后不断地对这些所有的鱼竿进行便利检测, 只要其中那个鱼漂有动静, 就将鱼钩拉上来.
钱七钓鱼方法:
钱七是一个大土豪, 他来的时候是由自己的专门司机开着名车将自己带过来的, 于是他将鱼钩交给自己的司机, 告诉他, 你帮我钓鱼, 等你钓完鱼, 下午的时候给我打电话, 我直接来拿鱼就可以了. 于是去忙自己的事了.

总结

通过上面的这个例子, 我们可以看出来张三, 李四, 王五, 赵六他们都有一个特性, 那就是等待鱼上钩自己等待, 将鱼拉上来也是自己干, 而钱七相比前面的四个人而言也就是等待鱼儿上钩是别人替自己等, 鱼拉上来也是别人帮自己拉上来, 而自己唯一要做的就是将钓鱼这件事发起, 然后交给某个人就可以了.
如果将上面的钓鱼的例子对应到我们的IO模型中的话, 那么前四种就是对应的同步IO, 即等待和数据搬迁都由自己来完成, 而最后一种就是对应的异步 IO, 数据搬迁和等待都不需要自己来完成, 自己唯一干的就是发起某个事件.同时张三对应的IO模型就是阻塞方式, 李四就是非阻塞方式, 王五为驱动方式, 赵六为多路转接模型, 钱七为异步方式

几个概念

同步IO事件由自己发起, 就绪事件的等待由自己完成, 数据的搬迁也是由自己来完成.

异步IO事件由自己发起, 就绪事件的等待, 数据的搬迁都由别人帮自己完成

轮询不断的检测就绪事件是否发生, 轮询是基于非阻塞接口.

IO多路转接一次可以监视多个文件描述符, 就好比赵六一次可以监视多个鱼竿

阻塞和非阻塞的不同

阻塞和非阻塞的不同之处在于等待方式的不同, 阻塞方式就是只要就绪事件没有发生, 则一直等待, 而非阻塞方式就是不断检测, 如果有就绪事件发生, 就处理就绪事件, 如果没有就绪事件就返回, 然后过一段时间时间再进行检测.

五种 IO 模型

阻塞方式在内核将数据准备好之间, 系统一直等待, 所有的套接字默认为阻塞方式.

非阻塞方式需要程序员不断循环反复尝试读写文件描述符.

信号驱动内核将数据准备好的时候, 于是便给当前应用程序发送一个SIGIO信号,当前应用进程收到这个信号的额时候, 于是便知道底层的就绪事件已经发生, 于是就进行 IO 操作

**IO多路转接**IO多路转接一次可以等待多个文件描述符的就绪事件

异步IO由内核在数据拷贝完成的时候通知应用进程(信号驱动对应的就是高速应用进程何时可以进行数据搬迁)

高级IO重要概念

同步IO VS 异步IO

同步IO在发出一个调用的时候, 在没有得到结果之前, 该调用不会返回, 但是一旦调用返回, 就得到返回值, 即由调用者主动等待调用结果.

异步IO调用在发出之后, 这个调用就会返回, 没有返回结果. 换言之就是当一个异步调用发出之后, 调用者不会立即等到结果, 而是在调用之后, 由被调用者通过状态通知调用者, 或者通过回调函数来处理这个函数.

非阻塞相关接口

fcntl

我们都知道文件描述符默认都是阻塞 IO

#include<unistd.h>
#include<fcntl.h>

int fcntl(int fd, int cmd, .../*arg*/);

其中 fd 为文件描述符, 表示要对哪一个文件描述符进行设置, cmd取值不同时代表了不同的方式

cmd = F_DUPFD 时代表复制一个文件描述符

cmd = FGETFD 或者 FSETFD 时代表获得文件描述符标记

实现一个非阻塞文件描述符

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

void SetNoBlock(int fd)
{
    int f1 = fcntl(fd, F_GETFL);
    if(fd < 0)
    {
        perror("fd");
        exit(1);
    }
    fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}
int main()
{
    SetNoBlock(0);
    while(1)
    {
        char buf[1024] = {0};
        ssize_t s = read(0, buf, sizeof(buf));
        if(s < 0)
        {
            perror("read");//底层未将数据准备好
            sleep(1);
            continue;
        }
        printf("input %s\n", buf);
    }
    return 0;
}

重定向

曾近我们学习过将数据重定向即就是将某个文件符关闭, 然后打开文件描述符,此时对关闭的那个文件描述符进行操作便会成为对文件的操作.

dup/dup2

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章