计算机网络之五种IO模型与阻塞IO

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

计算机网络之五种IO模型与阻塞IO

收录于专栏【计算机网络
本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

五种IO模型

阻塞IO

非阻塞IO

信号驱动IO

IO多路转接

异步IO

高级IO重要概念

[同步通信 vs 异步通信](#同步通信 vs 异步通信)

[阻塞 vs 非阻塞](#阻塞 vs 非阻塞)

其他高级IO

非阻塞IO

fcntl

实现函数SetNoBlock

轮询方式读取标准输入


五种IO模型

阻塞IO

**阻塞IO:**在内核中将数据准备好之前,系统调用会一直等待所有的套接字,默认都是阻塞方式。

阻塞IO是最常见的IO模型。

非阻塞IO

非阻塞IO:如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回 EWOULDBLOCK 错误码。

非阻塞 IO 往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询,这对 CPU 来说是较大的浪费,一般只有特定场景才使用。

信号驱动IO

信号驱动 IO:内核将数据准备好的时候,使用 SIGIO 信号通知应用程序进行 IO

IO多路转接

IO 多路转接:虽然从流程图上看起来和阻塞 IO 类似,实际上最核心在于 IO 多路转接能够同时等待多个文件描述符的就绪状态。

异步IO

异步 IO:由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)。

高级IO重要概念

这里需要强调几个重要的概念。

同步通信 vs 异步通信

同步和异步关注的是消息通信机制。

所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了;换句话说,就是由调用者主动等待这个调用的结果。

异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果;换句话说,当一个异步过程调用发出后,调用者不会立即得到结果;而是在调用发出后,被调用者通过状态、通知来通知者,或通过回调函数处理这个调用。

另外,我们回忆在多进程多线程的时候,也提到同步和互斥,这里的同步通信和进程之间的同步时完全不相干的该概念。

进程/线程同步也是进程/线程之间直接的制约关系

是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上的协调他们的工作次序而等待、传递信息所产生的制约关系。尤其是在访问临界资源的时候。

在看到同步这个词,一定要搞清楚大背景是什么,这个同步,是同步通信异步通信的同步,还是同步或互斥的同步。

阻塞 vs 非阻塞

阻塞和非阻塞关注的是程序员在等待调用的结果(消息,返回值)时的状态。

阻塞调用是调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才会返回。

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

其他高级IO

非阻塞 IO,记录锁,系统 V 流机制,I/O 多路转接(也叫 I/O 多路复用),readv 和 writev 函数以及存储映射 IO (mmap),这些统称为高级 IO。

后面我会重点介绍 I/O 多路转接

非阻塞IO

fcntl

一个文件描述符,默认都是阻塞 IO。

函数原型如下:

cpp 复制代码
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

传入的 cmd 的值不同,后面追加的参数也不相同。

fcntl 函数有5中功能:

复制一个现有的描述符 (cmd=F_DUPFD) 。

获得/设置文件描述符标记(cmd=F_GETFD 或 F_SETFD)。

获得/设置文件状态标记 (cmd=F_GETFL 或 F_SETFD)。

获得/设置异步 I/O 所有权 (cmd=F_GETOWN 或 F_SETOWN)。

获得/设置记录锁(cmd=F_GETLK,F_SETLK 或 F_SETLKW)。

我们此处只是使用第三种功能,获取/设置文件状态标记,就可以将一个文件描述符设置为非阻塞。

实现函数SetNoBlock

基于 fcntl,我们实现一个 SetNoBlock 函数,将文件描述符设置为非阻塞。

cpp 复制代码
void SetNoBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL);
    if (fl < 0)
    {
        perror("fcntl");
        return;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}

使用 F_GETFL 将当前的文件描述符的属性取出来 (这是一个位图)。

然后再使用 F_SETFL 将文件描述符设置回去,设置回去的同时,加上一个 O_NONBLOCK 参数。

轮询方式读取标准输入

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void SetNoBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL);
    if (fl < 0)
    {
        perror("fcntl");
        return;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}
int main()
{
    SetNoBlock(0);
    while (1)
    {
        char buf[1024] = {0};
        ssize_t read_size = read(0, buf, sizeof(buf) - 1);
        if (read_size < 0)
        {
            perror("read");
            sleep(1);
            continue;
        }
        printf("input:%s\n", buf);
    }
    return 0;
}
相关推荐
M1A137 分钟前
TCP协议详解:为什么它是互联网的基石?
后端·网络协议·tcp/ip
瓦特what?39 分钟前
关于C++的#include的超超超详细讲解
java·开发语言·数据结构·c++·算法·信息可视化·数据挖掘
共享家95271 小时前
linux-数据链路层
linux·网络·macos
祁同伟.1 小时前
【C++】动态内存管理
开发语言·c++
一只鲲1 小时前
40 C++ STL模板库9-容器2-vector
开发语言·c++
励志不掉头发的内向程序员2 小时前
C++基础——内存管理
开发语言·c++
jdlxx_dongfangxing2 小时前
从希格斯玻色子到 QPU:C++ 的跨维度征服
c++·量子计算·希格斯玻色子·高难度科普文
千里镜宵烛2 小时前
深入理解 Linux 线程:从概念到虚拟地址空间的全面解析
开发语言·c++·操作系统·线程
欧哈东哥2 小时前
【C++】标准库中用于组合多个值的数据结构pair、tuple、array...
java·数据结构·c++
青衫码上行3 小时前
【计算机网络 | 第7篇】物理层基本概念
计算机网络