计算机网络之五种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;
}
相关推荐
半盏茶香19 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
哎呦,帅小伙哦26 分钟前
Effective C++ 规则41:了解隐式接口和编译期多态
c++·effective c++
DARLING Zero two♡1 小时前
【初阶数据结构】逆流的回环链桥:双链表
c语言·数据结构·c++·链表·双链表
9毫米的幻想1 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++
德迅云安全-小钱1 小时前
跨站脚本攻击(XSS)原理及防护方案
前端·网络·xss
Cando学算法1 小时前
Codeforces Round 1000 (Div. 2)(前三题)
数据结构·c++·算法
王建文1 小时前
http请求获取客户端ip
网络协议·tcp/ip·http
字节高级特工1 小时前
【优选算法】5----有效三角形个数
c++·算法
荣--2 小时前
HiJobQueue:一个简单的线程安全任务队列
c++·编码
Cici_ovo3 小时前
wlan和vlan
网络·智能路由器