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