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整体来说比较简单,重点是下面的话题,多路转接

相关推荐
*小海豚*1 分钟前
在linux服务器上DNS正常,但是java应用调用第三方解析域名报错
java·linux·服务器
June`1 分钟前
muduo项目排查错误+测试
linux·c++·github·muduo网络库
春日见2 分钟前
如何创建一个PR
运维·开发语言·windows·git·docker·容器
DARLING Zero two♡11 分钟前
告别 Docker 命令行!Portainer+cpolar 让容器管理从局域网走向公网
运维·docker·容器
消失的旧时光-194317 分钟前
Linux 编辑器入门:nano 与 vim 的区别与选择指南
linux·运维·服务器
斯普信专业组19 分钟前
构建基于MCP的MySQL智能运维平台:从开源服务端到交互式AI助手
运维·mysql·开源·mcp
晓131327 分钟前
第七章 【C语言篇:文件】 文件全面解析
linux·c语言·开发语言
唐装鼠36 分钟前
Linux 下 malloc 内存分配机制详解
linux·malloc
予枫的编程笔记36 分钟前
【Linux入门篇】Linux运维必学:Vim核心操作详解,告别编辑器依赖
linux·人工智能·linux运维·vim操作教程·程序员工具·编辑器技巧·新手学vim
17(无规则自律)1 小时前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件