计算机网络之五种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;
}
相关推荐
愚润求学6 分钟前
【C++】vector常用方法总结
开发语言·c++·vector
louisgeek10 分钟前
MQTT 消息队列遥测传输
网络协议
春生黎至100534 分钟前
GZ073网络系统管理赛项赛题第1套模块A:网络构建解题笔记
运维·网络
IT程序媛-桃子35 分钟前
【网安面经合集】42 道高频 Web 安全面试题全解析(附原理+防御+思路)
运维·网络·安全·面试
蒜白41 分钟前
27--当路由器学会“防狼术“:华为设备管理面安全深度解剖(完整战备版)
网络·安全·网络工程师·交换机
赤秀1 小时前
C++模板初阶
开发语言·c++
山楂树の1 小时前
计算机网络 OSI参考模型
网络·计算机网络
菜萝卜子1 小时前
【计算机网络】记录一次校园网无法上网的解决方法
计算机网络
AdrichPro1 小时前
10、Linux C 网络编程(完整版)
linux·服务器·c语言·网络
半桔1 小时前
红黑树剖析
c语言·开发语言·数据结构·c++·后端·算法