Linux 非阻塞IO
1. fcntl()
在Linux操作系统中,fcntl()
是一个用于操作文件描述符的系统调用。它提供了多种功能,包括控制文件描述符的属性、管理文件锁定、设置文件的非阻塞模式等。
本文只截取了用于IO模型的
fcntl()
部分内容,fcntl()
的详细内容请看—>Linux fcntl函数
在打开文件时,如果不使用fcntl()
对其进行设置,这个文件就默认使用阻塞IO。非阻塞IO和信号驱动IO都需要手动调用fcntl()
才能使用。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, .../* arg */)
fd: 需要进行操作的文件描述符。
cmd: 指定要进行的操作。
F_GETFL
表示返回当前文件描述符的状态标志,如是否是非阻塞模式(O_NONBLOCK
)。F_SETFL
表示设置文件描述符的状态标志,在可变参数(arg
)中,输入要设置的状态标志,如O_NONBLOCK
(非阻塞模式)、O_ASYNC
(信号驱动模式)
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); // 设置非阻塞模式
//或
fcntl(fd, F_SETFL, flags | O_ASYNC); //设置信号驱动模式
2. 阻塞IO
非阻塞 IO 往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询。这对 CPU 来说是较大的浪费,一般只有特定场景下才使用。
非阻塞等待中,不论是数据未就绪还是读数据出错,recv()
的 返回值都是小于0,为了区分两者,c语言提供的 errno
记录了最后一次系统调用出错的错误信息。当底层数据没有就绪, errno
就会被设置为 EWOULDBLOCK
(EAGAIN
)。
//errno.h
#ifndef _ERRNO_H
#define _ERRNO_H//.......
#define EBADF 9 /* 文件描述符无效 */
#define ECHILD 10 /* 子进程不存在 */
#define EAGAIN 11 /* 资源暂时不可用,尝试重新调用 */
//.....
#endif /* _ERRNO_H */
使用非阻塞IO前,要先将文件描述符的状态标志设置为非阻塞模式:
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); // 设置非阻塞模式