Linux:谈谈阻塞式和非阻塞式IO

文章目录

本篇总结的核心内容就是非阻塞式IO,直接看代码

阻塞式和非阻塞式IO

阻塞式IO

如下所示是典型的阻塞式IO

cpp 复制代码
#include <iostream>
#include <unistd.h>
using namespace std;

int main()
{
    char buff[1024];
    while(true)
    {
        ssize_t n = read(0, buff, sizeof(buff) - 1);
        // 如果接收成功
        if(n > 0)
        {
            buff[n - 1] = 0;
            cout << "buffer get : " << buff << endl;
        }
        // 如果结束
        else if(n == 0)
        {
            cout << "read done" << endl;
            break;
        }
        else
        {
            cerr << "read error" << endl;
            break;
        }
    }
    return 0;
}

非阻塞式IO

那如果今天我们想把他更换为非阻塞式IO呢?就要用到前面所说的一个fcntl函数了:

这个函数的第二个参数是一个标记位,里面包含的是众多的common选项,当它获取成功之后,回返回一个当前文件的一个老的标记位,而如果想要设置的话就可以用这个老的标记位按位与进去一个新的,这样就设置好了所谓的非阻塞式标记位,下面用代码来实现:

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
#include <cstring>
using namespace std;

void SetNonblock(int fd)
{
    int fl = fcntl(fd, F_GETFL);
    if (fl < 0)
    {
        cerr << "fcntl" << endl;
        return;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
    cout << "set " << fd << " nonblock success" << endl;
}

int main()
{
    char buff[1024];
    SetNonblock(0);
    while (true)
    {
        ssize_t n = read(0, buff, sizeof(buff) - 1);
        // 如果接收成功
        if (n > 0)
        {
            buff[n - 1] = 0;
            cout << "buffer get : " << buff << endl;
        }
        // 如果结束
        else if (n == 0)
        {
            cout << "read done" << endl;
            break;
        }
        else
        {
            cerr << "read error"
                 << ", n : " << n << ", error : " << errno << " , strerror : " << strerror(errno) << endl;
            sleep(1);
        }
    }
    return 0;
}

由运行结果可以看出,直接运行失败了,返回值是-1,并且在错误码的信息中可以看到是资源没有就绪

上图所示的就是非阻塞式轮询了,由于用户输入的数据太慢了,所以在实际的查询中,绝大多数情况下都是查询不到消息的,而由此得出的一个重要结论是,如果被设置为非阻塞式轮询,那么如果底层的fd对应的数据没有就绪,那么像这样的recvfrom或者是read的接口,返回值就会以出错的形式进行返回

但是实际上,这真的出错了吗?答案必然是没有的,出错是分情况的,一种是真的出错了,比如这个文件描述符被关闭了,或者是其他的意外情况,但是也可能是因为资源没有就绪的情况,所以避免的方式就是通过error错误码来进行区分,由此可以看出的一点是,非阻塞式是会进行轮询的检查的,并且不会阻塞在这个函数这里,而是会一直的去检查对应的信息,如果资源没有就绪,还可以去做其他的事,等资源就绪了再进行一些其他的操作

阻塞式和非阻塞式IO整体来说比较简单,重点是下面的话题,多路转接

相关推荐
律宏阔4 小时前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔4 小时前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴4 小时前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千4 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei374 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei374 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei374 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
judezh4 小时前
api 容器一直 unhealthy?我把一个 Agent 运行时的健康检查逐条拆了,查出四个问题
运维·docker
GeW5 小时前
制造业高端化,为什么必须重估Linux和数据库?
linux
百万蹄蹄向前冲5 小时前
双端同步!云服务器装最新Node.js v26.10全过程追踪
服务器·人工智能·node.js