【高级IO】非阻塞IO

fcntl函数

一个文件描述符, 默认都是阻塞IO,通过fcntl把阻塞文件描述符改为非阻塞

传入的cmd的值不同, 后面追加的参数也不相同

fcntl函数有5种功能:

  • 复制一个现有的描述符(cmd=F_DUPFD).
  • 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
  • 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
  • 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
  • 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).

我们此处只是用第三种功能, 获取/设置文件状态标记, 就可以将一个文件描述符设置为非阻塞.

 实现函数SetNoBlock

设置文件描述符为非阻塞,固定写法就是下面的写法

void SetNonBlock(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参数 

其实还有另一种做法,就是在open打开文件的时候,就可以设置文件描述符为非阻塞,一般是上面的写法

实例

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <cerrno>
#include <cstring>

using namespace std;

void SetNonBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL);  //获取文件状态
    if (fl < 0)
    {
        perror("fcntl");
        return;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);  //设置文件状态为非阻塞
    cout << " set " << fd << " nonblock done" << endl;
}

int main()
{
    char buffer[1024];
    SetNonBlock(0);
    sleep(1);
    while (true)
    {
        printf("Please Enter# ");
        fflush(stdout);

        ssize_t n = read(0, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n - 1] = 0;
            cout << "echo : " << buffer << endl;
        }
        else if (n == 0)
        {
            cout << "read done" << endl;
            break;
        }
        else
        {
            // 1. 设置成为非阻塞,如果底层fd数据没有就绪,recv/read/write/send, 返回值会以出错的形式返回
            // 2. a. 真的出错 b. 底层没有就绪
            // 3. 我怎么区分呢?通过errno区分!!!
            if (errno == EWOULDBLOCK)   //出错码是EWOULDBLOCK,就是底层没有就绪,不是真的出错
            {
                cout << "0 fd data not ready, try again!" << endl;
                // do_other_thing();   //非阻塞返回后进程可以做别的事情,不用阻塞在那
                sleep(1);
            }
            else   //真的出错
            {
                cerr << "read error, n = " << n << "errno code: "
                     << errno << ", error str: " << strerror(errno) << endl;
            }
        }
    }

    return 0;
}

注意: 

1. 设置成为非阻塞,如果底层fd数据没有就绪,recv/read/write/send, 返回值会以出错的形式返回

2. a. 真的出错 b. 底层没有就绪

3. 我怎么区分呢?通过errno区分!!!errno是 EWOULDBLOCK代表底层资源没有就绪,不是真的出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱敲代码的奇点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值