《unix高级环境编程》高级 I/O——非阻塞 I/O

非阻塞 I/O 使我们可以调用 open、write 和 read 这样的 I/O 操作,并使这些操作不会永远阻塞。如果这种操作不能完成,则立即出错返回,表示该操作若继续执行将阻塞。
对于一个给定的文件描述符由以下两种方法可以对其指定非阻塞 I/O:
  1. 若调用 open 获得描述符,则可指定 O_NONBLOCK 标志;
  2. 对已打开的描述符,可以使用 fcntl,由该函数打开 O_NONBLOCK 文件状态标志;

测试程序:

#include "apue.h"
#include <fcntl.h>

void set_fl(int fd, int flags);
void clr_fl(int fd, int flags);

char buf[500000];

int main(void)
{
    int ntowrite, nwrite;
    char *ptr;

    ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
    fprintf(stderr, "read %d bytes.\n",ntowrite);

    set_fl(STDOUT_FILENO, O_NONBLOCK);

    ptr = buf;
    while(ntowrite > 0)
    {
        errno = 0;
        nwrite = write(STDOUT_FILENO, ptr, ntowrite);
        fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);

        if(nwrite > 0)
        {
            ptr += nwrite;
            ntowrite -= nwrite;
        }
    }
    clr_fl(STDOUT_FILENO, O_NONBLOCK);

    exit(0);
}


//设置文件描述符标志
void set_fl(int fd, int flags)
{
    int val;
    //获取文件描述符标志
    if((val = fcntl(fd, F_GETFL, 0)) < 0)
        err_sys("fcntl F_GETFL error");
    val |= flags;//添加描述符标志flags
    //设置文件描述符标志
    if(fcntl(fd, F_SETFL, val) < 0)
        err_sys("fcntl F_SETFL error");
}
//清除文件描述符标志
void clr_fl(int fd, int flags)
{
    int val;
    //获取文件描述符标志
    if((val = fcntl(fd, F_GETFL, 0)) < 0)
        err_sys("fcntl F_GETFL error");
    val &= ~flags;//清除描述符标志flags
    //设置文件描述符标志
    if(fcntl(fd, F_SETFL, val) < 0)
        err_sys("fcntl F_SETFL error");
}

输出结果:

./test </tmp/tmp.sh> temp.file
read 2778 bytes.
nwrite = 2778, errno = 0

fcntl 函数

/*
*fcntl函数
*功能:操纵文件描述符,设置已打开的文件的属性*/
int fcntl(int fd, int cmd, ... /* arg */ );
/*说明:
*cmd的取值可以如下:
*复制文件描述符
*F_DUPFD (long)
*设置/获取文件描述符标志
*F_GETFD (void)
*F_SETFD (long)
*设置/获取文件状态标志
*F_GETFL (void)
*F_SETFL (long)
*获取/设置文件锁
*F_GETLK
*F_SETLK,F_SETLKW
*/

参考资料:
《UNIX高级环境编程》

你可能感兴趣的:(IO,非阻塞IO)