计算机网络之五种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;
}
相关推荐
倒头就睡的小比特1 天前
算法竞赛C++常用的STL
c++·算法
weilx12341 天前
C++笔记-文件IO-<fcntl.h>
c++
虎头金猫1 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
Smileyqp沛沛1 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车1 天前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光1 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wuyk5551 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
吞下星星的少年·-·1 天前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁1 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven1 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法