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

发布于:2024-04-11 ⋅ 阅读:(34) ⋅ 点赞:(0)

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

阻塞式和非阻塞式IO

阻塞式IO

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

#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选项,当它获取成功之后,回返回一个当前文件的一个老的标记位,而如果想要设置的话就可以用这个老的标记位按位与进去一个新的,这样就设置好了所谓的非阻塞式标记位,下面用代码来实现:

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