高级IO——非阻塞IO

在上一篇介绍非阻塞IO时,我们可以认识到,非阻塞IO在条件不成立时直接返回。

通常我们在设置接口是阻塞还是非阻塞的时候,有两种方案:

    (1)将文件描述符设置为非阻塞式文件描述符;

    (2)通过传递特殊选项,让接口本身以非阻塞方式调用。


  • fcntl

一个文件描述符,默认都是阻塞IO。

fcntl的函数原型如下:


fcntl可以改变已经打开的文件性质。针对cmd的值,fcntl能够接受第三个参数arg(可变参数列表)。传入的cmd的值不同,后面追加的参数也不相同。

fcntl函数有五种功能:

    (1)复制一个现有的描述符(cmd = F_DUPFD);

    (2)获得/设置文件描述符标记(cmd = FGETFD 或 FSETFD)

    (3)获得/设置文件状态标记(cmd = FGETFL 或 FSETFL)

    (4)获得/设置异步I/O所有权(cmd = FGETOWN 或 FSETOWN)

    (5)获得/设置记录锁(cmd = FGETLK 或 FSETKW)

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


  • 实现函数SetNoBlock

基于fcntl,我们实现一个SetNoBlock函数,将文件描述符设置为非阻塞。

#include 
#include

void SetNoBlock(int fd){
    int fl = fcntl(fd,F_GETFL);//使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图)
    if(fl < 0){
        perror("fcntl");
        return;
    }
    fcntl(fd,F_SETFL,fl | O_NONBLOCK);//再使用F_SETFL将文件描述符设置回去,设置回去的同时,加上一个O_NONBLOCK参数
    return;
}


  • 轮询方式读取标准输入
#include
#include 
#include
#include

void SetNoBlock(int fd){
    int fl = fcntl(fd,F_GETFL);
    if(fl < 0){
        perror("fcntl");
        return;
    }
    fcntl(fd,F_SETFL,fl | O_NONBLOCK);
    return;
}

int main(){
    SetNoBlock(0);//将标准输入设为非阻塞
    while(1){
        char buf[1024] = {0};
        ssize_t num = read(0,buf,sizeof(buf)-1);
        if(num == -1 && errno == EAGAIN){
            printf("stdin data is not ready\n");
            sleep(1);
            continue;
        }
        printf("input:%s\n",buf);
    }
    return 0;
}

这个程序里的EAGAIN的定义如下:






你可能感兴趣的:(Linux)