fcntl
是一个系统调用,用于获取或设置与文件描述符 fd
关联的文件的各种属性或状态标志。在 Linux 中,几乎所有的资源都被视为文件,因此 fcntl
可以应用于几乎任何类型的资源,包括普通文件、套接字、管道等。网络编程上,常用这个函数设置把套接字设置为非阻塞或者异步等。
函数原型
int fcntl(int fd, int cmd, ...);
函数接受三个参数:
fd
:文件描述符,是一个非负整数,用于标识一个打开的文件或资源。cmd
:一个命令,用于指定要执行的操作。这个命令决定了fcntl
函数的行为以及是否需要第三个参数。...
:这是一个可变参数列表,其内容和必要性取决于cmd
的值。对于F_GETFL
和F_SETFL
命令,第三个参数是一个整数(当使用F_SETFL
时)或0
(当使用F_GETFL
时)。
参数解释
fd
:如上所述,是文件描述符。cmd
:指定要执行的操作。对于获取或设置文件属性,常用的命令有:F_GETFL
:获取文件的状态标志。此时,第三个参数应为0
,函数返回当前的文件状态标志。F_SETFL
:设置文件的状态标志。此时,第三个参数是一个整数,包含了要设置的新状态标志。
- 第三个参数:根据
cmd
的值而变化。对于F_GETFL
,它不重要(通常传递0
);对于F_SETFL
,它包含了要设置的新文件状态标志。
返回值
- 成功时,
fcntl
返回文件的状态标志(对于F_GETFL
命令)或0
(对于F_SETFL
命令和其他一些命令)。 - 失败时,返回
-1
,并设置errno
以指示错误原因。
假设你想获取一个文件描述符的状态标志,你可以这样做:
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
// 处理错误
}
如果你想设置文件描述符为非阻塞模式,你可以这样做:
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
// 处理错误
}
flags |= O_NONBLOCK; // 添加非阻塞标志
if (fcntl(fd, F_SETFL, flags) == -1) {
// 处理错误
}
这里,我们首先获取了文件描述符的当前状态标志,然后添加了非阻塞标志,并设置了新的状态标志。
设置异步的时候,要用到信号这个东西。
在Linux环境下,用于设置文件描述符(fd
)以接收异步I/O通知。它主要通过fcntl
系统调用和signal
函数来实现。结构如下:
- 将APP进程号告诉驱动程序:
fcntl(fd, F_SETOWN, getpid());
fcntl
是一个功能强大的系统调用,用于获取或设置文件描述符的属性。F_SETOWN
是一个命令,用于设置文件描述符的所有者进程ID。getpid()
函数返回当前进程的进程ID。- 这行代码的作用是将文件描述符
fd
的所有者设置为当前进程。这是必要的,因为异步I/O通知会发送给文件描述符的所有者进程。
- 使能异步通知
int flag;
flag = fcntl(fd, F_GETFL);
flag |= O_ASYNC;
fcntl(fd, F_SETFL, flag);
- 首先,通过
fcntl(fd, F_GETFL)
获取文件描述符fd
的当前状态标志。 - 然后,使用位或操作(
|=
)将O_ASYNC
标志添加到当前状态标志中。O_ASYNC
标志用于启用对文件描述符的异步I/O操作。当文件描述符有I/O条件满足时(例如,有数据可读),将向进程发送SIGIO
信号。 - 最后,通过
fcntl(fd, F_SETFL, flag)
将更新后的状态标志设置回文件描述符fd
。
- 设置信号处理函数:
signal(SIGIO, handler);
signal
函数用于设置信号处理程序。SIGIO
是一个信号,当文件描述符有I/O条件满足时,内核会向进程发送这个信号。handler
是一个用户定义的函数,当SIGIO
信号被接收时,这个函数会被调用。- 这行代码的作用是将
SIGIO
信号的处理程序设置为handler
函数。
我们可以将文件描述符fd
的所有者设置为当前进程,并启用异步I/O通知。当文件描述符fd
有I/O条件满足时(例如,有数据可读),内核会向当前进程发送SIGIO
信号,然后调用用户定义的handler
函数来处理这个信号。这是实现异步I/O的一种有效方式,允许进程在等待I/O操作完成的同时继续执行其他任务。