目录
- 前言
- [一、fcntl 函数基础篇](#一、fcntl 函数基础篇)
-
- [1.1 fcntl 函数原型](#1.1 fcntl 函数原型)
- [1.2 常见的用途](#1.2 常见的用途)
-
- [1.2.1 获取和设置文件状态标志](#1.2.1 获取和设置文件状态标志)
- [1.2.2 文件锁定](#1.2.2 文件锁定)
- [1.2.3 更改文件描述符的属性](#1.2.3 更改文件描述符的属性)
- [1.3 错误处理](#1.3 错误处理)
- [1.4 示例代码](#1.4 示例代码)
- [二、fcntl 函数深度篇](#二、fcntl 函数深度篇)
-
- [2.1 复制文件描述符](#2.1 复制文件描述符)
-
- [2.1.1 `F_DUPFD`](#2.1.1
F_DUPFD
) - [2.1.2 `F_DUPFD_CLOEXEC`](#2.1.2
F_DUPFD_CLOEXEC
) - [2.1.3 二者对比](#2.1.3 二者对比)
- [2.1.4 `FD_CLOEXEC`标志的意义](#2.1.4
FD_CLOEXEC
标志的意义)
- [2.1.1 `F_DUPFD`](#2.1.1
- [2.2 获取/设置文件描述符标志](#2.2 获取/设置文件描述符标志)
-
- [2.2.1 `F_GETFD`](#2.2.1
F_GETFD
) - [2.2.2 `F_SETFD`](#2.2.2
F_SETFD
)
- [2.2.1 `F_GETFD`](#2.2.1
- [2.3 获取/设置文件状态标志](#2.3 获取/设置文件状态标志)
-
- [2.3.1 `F_GETFL`](#2.3.1
F_GETFL
) - [2.3.2 `F_SETFL`](#2.3.2
F_SETFL
)
- [2.3.1 `F_GETFL`](#2.3.1
- [2.4 获取/设置记录锁](#2.4 获取/设置记录锁)
-
- [2.4.1 `F_GETLK`](#2.4.1
F_GETLK
) - [2.4.2 `F_SETLK`](#2.4.2
F_SETLK
) - [2.4.3 `F_SETLKW`](#2.4.3
F_SETLKW
) - [2.4.4 结构体 flock](#2.4.4 结构体 flock)
- [2.4.1 `F_GETLK`](#2.4.1
- [2.5 获取/设置异步I/O所有权](#2.5 获取/设置异步I/O所有权)
-
- [2.5.1 `F_SETOWN `](#2.5.1
F_SETOWN
) - [2.5.2 `F_GETOWN`](#2.5.2
F_GETOWN
)
- [2.5.1 `F_SETOWN `](#2.5.1
- [2.6 处理异步 I/O 操作时的信号通知](#2.6 处理异步 I/O 操作时的信号通知)
-
- [2.6.1 `F_SETSIG`](#2.6.1
F_SETSIG
) - [2.6.2 `F_GETSIG`](#2.6.2
F_GETSIG
)
- [2.6.1 `F_SETSIG`](#2.6.1
- 三、参考链接
前言
fcntl 函数是一个在 UNIX 和类 UNIX 系统(如 Linux)上用来操作文件描述符的系统调用。它可以用于改变文件描述符的属性或状态,或者执行基本的控制操作。fcntl 函数非常强大且灵活,常用于实现各种文件和进程间通信的功能。
一、fcntl 函数基础篇
1.1 fcntl 函数原型
在 C 语言中,fcntl 的函数原型定义如下:
c
#include <fcntl.h>
#include <unistd.h>
int fcntl(int fd, int cmd, ... /* arg */ );
参数说明:
- fd: 文件描述符,指定要操作的文件或套接字的描述符。
- cmd: 控制命令,指示要执行的操作类型。常见的命令包括:
- 复制一个现有的描述符:
F_DUPFD :.复制文件描述符
F_DUPFD_CLOEXEC:复制文件描述符,设置FD_CLOEXEC标志- 获得/设置文件状态标记:
F_GETFL: 获取文件描述符的当前状态标志。
F_SETFL: 设置文件描述符的状态标志。- 获得/设置文件描述符标记:
F_GETFD: 获取文件描述符的内部标志。
F_SETFD: 设置文件描述符的内部标志。- 获得/设置异步I/O所有权:
F_GETOWN:获得异步I/O所有权
F_SETOWN:设置异步I/O所有权- 获得/设置记录锁:
F_GETLK: 获取文件锁定信息。
F_SETLK: 设置文件锁定信息。
F_SETLKW: 以阻塞方式设置文件锁定信息。
-
... arg: 可选的参数,根据不同的 cmd 值提供额外的信息。例如,对于 F_SETFL 命令,可以传递新的状态标志。
-
返回值
成功时返回命令的结果,通常是状态标志或锁信息。
失败时返回 -1,并设置 errno 以指示错误类型。
1.2 常见的用途
1.2.1 获取和设置文件状态标志
可以获取和修改文件描述符的标志,比如设置文件为非阻塞模式。
c
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); // 将这个描述符设置为非阻塞模式
1.2.2 文件锁定
可用于实现文件锁定机制,防止多个进程同时写入同一文件。
c
struct flock lock;
lock.l_type = F_WRLCK; // 请求写锁
lock.l_whence = SEEK_SET; // 从文件开始处锁定
lock.l_start = 0; // 从文件开始位置
lock.l_len = 0; // 锁定整个文件
fcntl(fd, F_SETLK, &lock); // 设置锁定
1.2.3 更改文件描述符的属性
可以动态更改文件描述符的功能,例如将其设置为异步I/O工作模式或实时信号。
1.3 错误处理
使用 fcntl 函数时,如果返回值为 -1,可以通过 errno 获取具体错误信息。常见的错误包括:
EBADF: 提供的文件描述符无效。
EINTR: 操作被信号中断。
EINVAL: 指定的命令无效或者参数不符合规范。
1.4 示例代码
以下是一个简单的使用 fcntl 函数的示例,演示如何将一个文件描述符设置为非阻塞模式:
c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("open");
return 1;
}
// 获取当前的文件状态标志
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
perror("fcntl get");
return 1;
}
// 设置为非阻塞模式
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl set");
return 1;
}
// 关闭文件描述符
close(fd);
return 0;
}
二、fcntl 函数深度篇
基础篇只是针对fcntl 函数做了一个简单的概括性描述,下面通过一些demo与讲解加深
对fcntl 函数功能的理解。
2.1 复制文件描述符
fcntl 函数中的 F_DUPFD 和 F_DUPFD_CLOEXEC 命令用于复制一个文件描述符(file descriptor),并为新描述符分配一个最小的非负整数值。这两个命令在处理文件描述符的管理时非常有用,尤其是在需要动态分配文件描述符的情况下。
2.1.1 F_DUPFD
- 命令: F_DUPFD
- 功能: 创建一个新的文件描述符,该描述符是现有文件描述符的副本。新的文件描述符将从指定的最小文件描述符值开始分配,使用大于或等于arg参数的编号最低的可用文件描述符。新描述符与旧 fd共享同一文件表项。但是,新描述符有它自己的一套文件描述符标志,其
FD_CLOEXEC
文件描述符标志被清除〈这表示该描述符在 exec 时仍保持打开状态)。 - 用法:
c
int fcntl(int fd, F_DUPFD, int n);
参数说明:
fd: 要复制的原始文件描述符。
n: 分配的新文件描述符的起始值。如果可用,新的文件描述符将返回一个大于或等于 n 的最小的文件描述符。
返回值:
如果成功,则返回新的文件描述符。
失败时返回 -1,并设置 errno。
2.1.2 F_DUPFD_CLOEXEC
- 命令: F_DUPFD_CLOEXEC
- 功能: 类似于 F_DUPFD,但在创建的新文件描述符上设置了
FD_CLOEXEC
标志。这意味着如果当前进程调用 exec 系列函数时,将自动关闭这个文件描述符。 - 用法:
c
int fcntl(int fd, F_DUPFD_CLOEXEC, int n);
参数说明:
fd: 要复制的原始文件描述符。
n: 分配的新文件描述符的起始值。
返回值:
如果成功,则返回新的文件描述符。
失败时返回 -1,并设置 errno。
2.1.3 二者对比
dup
和 F_DUPFD
都不会保留 FD_CLOEXEC 标志;
使用 F_DUPFD_CLOEXEC 会将新描述符的 FD_CLOEXEC 标志设置为 1。
fcntl(fd, F_GETFD, 0) 获取的标志用于查询指定文件描述符的状态,包括 FD_CLOEXEC。如果该标志被设置,返回值为 1。如果没有设置,返回值为 0。
下面通过一个demo理解二者的区别。
c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
//fd 设置标记 fcntlFd 不设置 fcntlCloFd 设置 dupFd 不设置
int fd = open("./fcntl_F_DUPFD_CLOEXEC", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0775);
int fcntlFd = fcntl(fd, F_DUPFD, 0);
int fcntlCloFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
int dupFd = dup(fd);
//通过fcntl(fd, F_GETFD, 0);获取状态标记
int fdFlag = fcntl(fd, F_GETFD, 0);
int fcntlFdFlag = fcntl(fcntlFd, F_GETFD, 0);
int fcntlCloFdFlag = fcntl(fcntlCloFd, F_GETFD, 0);
int dupFdFlag = fcntl(dupFd, F_GETFD, 0);
// 结果是:fdFlag=1, fcntlFdFlag=0, fcntlCloFdFlag=1, dupFdFlag=0
printf("fdFlag=%d, fcntlFdFlag=%d, fcntlCloFdFlag=%d, dupFdFlag=%d\n",
fdFlag,fcntlFdFlag,fcntlCloFdFlag,dupFdFlag);
close(fd);
close(fcntlFd);
close(fcntlCloFd);
close(dupFd);
return 0;
}
2.1.4 FD_CLOEXEC
标志的意义
文件描述符标志FD_CLOEXEC
。用来表示该描述符在执行完fork+exec系列函数创建子进程时会自动关闭,以防止它们被传递给子进程。为什么要这样做呢?
因为当一个进程调用exec系列函数(比如execve)来创建子进程时,所有打开的文件描述符都会被传递给子进程。如果文件描述符没有设置FD_CLOEXEC标志,这些文件将保持打开状态并继续对子进程可见。这可能导致潜在的安全风险或者意外行为。
2.2 获取/设置文件描述符标志
fcntl 函数中的 F_GETFD 和 F_SETFD 命令用于获取和设置文件描述符的标志,这在操作文件描述符的行为时非常重要。
2.2.1 F_GETFD
- 功能: 获取指定文件描述符的标志。
- 用法:
c
int fcntl(int fd, F_GETFD);
- 参数说明:
fd: 要查询状态的文件描述符。 - 返回值:
返回文件描述符的标志,如果失败则返回 -1,并设置 errno。主要的标志包括:
FD_CLOEXEC: 文件描述符在 exec 系列调用时会被关闭。如果该标志被设置,返回值包含该标志。 - 常见的标志值:
如果返回值与 FD_CLOEXEC 持平,表示标志已设置;如果返回值包含 0,表示没有设置。
2.2.2 F_SETFD
功能: 设置指定文件描述符的标志。
用法:
c
int fcntl(int fd, F_SETFD, int flags);
- 参数说明:
fd: 要设置状态的文件描述符。
flags: 新的状态标志,可以是以下值之一,或者是它们的组合:
FD_CLOEXEC: 设置该标志,表示在调用 exec 系列函数时关闭文件描述符。 - 返回值:
如果成功,返回 0。失败时返回 -1,并设置 errno。
文件描述符的FD_CLOEXEC
标志可以通过三个方法得到:
1、调用open函数是,指定 O_CLOEXEC
2、通过fcntl函数使用F_DUPFD_CLOEXEC复制文件描述符,新的描述符就是FD_CLOEXEC
3、通过fcntl函数使用F_SETFD直接设置FD_CLOEXEC。
2.3 获取/设置文件状态标志
fcntl 函数中的 F_GETFL
和 F_SETFL
命令用于获取和设置文件的状态标志,这些标志控制文件的行为和特性。
文件状态标志如下表:
文件状态标志 | 说明 | 十六进制值 |
---|---|---|
O_RDONLY | 只读打开 | 0x0 |
O_WRONLY | 只写打开 | 0x1 |
O_RDWR | 读、写打开 | 0x2 |
O_APPEND | 追加写 | 0x400 |
O_NONBLOCK | 非阻塞模式 | 0x800 |
O_SYNC | 等待写完成(数据和属性) | |
O_DSYNC | 等待写完成(仅数据) | |
O_RSYNC | 同步读和写 | |
O_FSYNC | 等待写完成 | |
O_ASYNC | 异步IO | 0x2000 |
2.3.1 F_GETFL
- 功能: 获取指定文件描述符的状态标志。
- 用法:
c
#include <fcntl.h>
int fcntl(int fd, F_GETFL);
- 参数说明:
fd: 要查询状态的文件描述符。 - 返回值:
返回文件描述符的状态标志。如果成功,则是一个标志位的位掩码,失败时返回 -1,并设置 errno。
访问方式标志:O_RDONLY 、O_WRONLY、O_RDWR。这3个值是互斥的,因此首先必须用屏蔽O_ACCMODE取得访问方式位,然后将结果与这3个值中的每一个相比较。 - 常见的状态标志:
O_RDONLY: 只读模式。
O_WRONLY: 只写模式。
O_RDWR: 读写模式。
O_APPEND: 写操作时将偏移量移到文件末尾。
O_NONBLOCK: 以非阻塞模式操作。
O_CLOEXEC: 文件描述符在执行 exec 系列函数时会关闭。
2.3.2 F_SETFL
- 功能: 设置指定文件描述符的状态标志。
- 用法:
c
#include <fcntl.h>
int fcntl(int fd, F_SETFL, int flags);
- 参数说明:
fd: 要设置状态的文件描述符。
flags: 新的状态标志,可以是以下值之一,或者是它们的组合。常用的标志包括:
O_APPEND
O_NONBLOCK
其他任何适用的标志(例如 O_RDONLY、O_WRONLY 等)。 - 返回值:
如果成功,返回 0。失败时返回 -1,并设置 errno。
在Linux上,只能设置这5个文件状态标志:O_APPEND、 O_ASYNC、 O_DIRECT、 O_NOATIME、O_NONBLOCK,其中最常用的是将文件描述符设置成非阻塞(O_NONBLOCK),特别是在网络编程中很常见。
2.4 获取/设置记录锁
在 Unix 和类 Unix 系统中,fcntl 函数提供了用于记录锁(record locks)的功能,通过命令 F_GETLK
、F_SETLK
和 F_SETLKW
来实现。这些命令用于获取、设置和管理文件的记录锁,帮助实现进程间的同步。
Linux实现了POSIX标准化的传统("进程相关")UNIX记录锁。
记录锁(record locking)的功能是:当一个进程正在读或修改文件的某个部分时,它可以阻止其他进程修改同一文件区。对于UNIX系统而言,"记录"这个词是一种误用,因为UNIX系统内核根本没有使用文件记录这种概念。更适合的术语可能是字节范围锁(byte-rangelocking),因为它锁定的只是文件中的一个区域(也可能是整个文件)。
F_SETLK、F_SETLKW和F_GETLK用于获取、释放和测试记录锁(也称为字节范围、文件段或文件区域锁)的存在。使用记录锁时,第三个参数是指向
struct flock
结构的指针。
2.4.1 F_GETLK
- 功能: 获取文件的锁的状态。
- 用法:
c
#include <fcntl.h>
#include <unistd.h>
struct flock lock;
lock.l_type = F_RDLCK; // 读取锁或写入锁的类型
lock.l_whence = SEEK_SET; // 锁的起始位置
lock.l_start = 0; // 从文件的开始位置锁定
lock.l_len = 0; // 锁定整个文件
int result = fcntl(fd, F_GETLK, &lock); // fd 是文件描述符
- 参数说明:
fd: 要获取锁状态的文件描述符。
&lock: 指向 flock 结构的指针,该结构包含了锁的信息。 - 返回值:
返回 0 表示成功,若出现错误则返回 -1,并设置 errno。
在成功时,可以通过检查 lock.l_type 来确定锁的状态。如果 l_type 被设置为 F_UNLCK,则表示没有其他进程持有该锁。如果是 F_RDLCK 或 F_WRLCK,则表示相应的锁已经被其他进程持有。
2.4.2 F_SETLK
- 功能: 设置文件的锁。如果锁失败,不会阻塞。
- 用法:
c
struct flock lock;
// 设置锁的信息
lock.l_type = F_WRLCK; // 写入锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁定整个文件
int result = fcntl(fd, F_SETLK, &lock); // 尝试设置锁
- 参数说明:
&lock: 指向 flock 结构的指针,定义需要设置的锁的类型和范围。 - 返回值:
返回 0 表示成功,若无法锁定则返回 -1,并设置 errno。
当返回 -1 时,常见的 errno 值为 EACCES 或 EAGAIN,表示锁已被其他进程持有。
2.4.3 F_SETLKW
功能: 设置文件的锁,和 F_SETLK 类似,但如果锁失败则阻塞直到成功。
用法:
c
struct flock lock;
// 设置锁的信息
lock.l_type = F_WRLCK; // 写入锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁定整个文件
int result = fcntl(fd, F_SETLKW, &lock); // 阻塞直到成功
- 参数说明:
同样使用 &lock,配置结构。 - 返回值:
同样返回 0 表示成功且锁定成功。若发生错误返回 -1,并设置 errno。成功是阻塞等待获得锁。
2.4.4 结构体 flock
在以上命令中,使用的 flock 结构体定义如下:
c
struct flock {
short l_type; // 锁的类型:F_RDLCK, F_WRLCK 或 F_UNLCK
short l_whence; // 锁偏移基准(SEEK_SET,SEEK_CUR,SEEK_END)决定l_start位置*
off_t l_start; // 从文件的哪个位置开始 锁定区域的开头位置
off_t l_len; // 锁定的字节数, 0 表示锁定到文件的末尾 锁定区域的大小
pid_t l_pid; // 锁的拥有者的进程 ID
};
l_whence
、l_start
、l_len
这三个参数用于分段对文件加锁,若对整个文件加锁,则:l_whence
= SEEK_SET,l_start
= 0,l_len
= 0;
l_type
有三种状态 :
F_RDLCK
建立一个供读取用的锁定,允许其他进程读该文件,但不允许其他进程写该文件;
F_WRLCK
建立一个供写入用的锁定,不允许其他进程读、写该文件;
F_UNLCK
删除之前建立的锁定
l_whence 也有三种方式:
SEEK_SET
以文件开头为锁定的起始位置。
SEEK_CUR
以目前文件读写位置为锁定的起始位置
SEEK_END
以文件结尾为锁定的起始位置。
c
#include "filelock.h"
/* 设置一把读锁 */
int readLock(int fd, short start, short whence, short len)
{
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_start = start;
lock.l_whence = whence;//SEEK_CUR,SEEK_SET,SEEK_END
lock.l_len = len;
lock.l_pid = getpid();
// 阻塞方式加锁
if(fcntl(fd, F_SETLKW, &lock) == 0)
return 1;
return 0;
}
/* 设置一把读锁 , 不等待 */
int readLocknw(int fd, short start, short whence, short len)
{
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_start = start;
lock.l_whence = whence;//SEEK_CUR,SEEK_SET,SEEK_END
lock.l_len = len;
lock.l_pid = getpid();
// 非阻塞方式加锁
if(fcntl(fd, F_SETLK, &lock) == 0)
return 1;
return 0;
}
/* 设置一把写锁 */
int writeLock(int fd, short start, short whence, short len)
{
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_start = start;
lock.l_whence = whence;
lock.l_len = len;
lock.l_pid = getpid();
//阻塞方式加锁
if(fcntl(fd, F_SETLKW, &lock) == 0)
return 1;
return 0;
}
/* 设置一把写锁 */
int writeLocknw(int fd, short start, short whence, short len)
{
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_start = start;
lock.l_whence = whence;
lock.l_len = len;
lock.l_pid = getpid();
//非阻塞方式加锁
if(fcntl(fd, F_SETLK, &lock) == 0)
return 1;
return 0;
}
/* 解锁 */
int unlock(int fd, short start, short whence, short len)
{
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_start = start;
lock.l_whence = whence;
lock.l_len = len;
lock.l_pid = getpid();
if(fcntl(fd, F_SETLKW, &lock) == 0)
return 1;
return 0;
}
2.5 获取/设置异步I/O所有权
F_GETOWN
和F_SETOWN
是与文件描述符相关的控制命令,它们用于获取和设置与文件描述符关联的异步 I/O 所属的进程或进程组。这两个命令主要在 POSIX 标准中使用,尤其是在 Unix 或 Linux 系统中。
这两个命令主要用于异步 I/O 功能,特别是在信号处理和进程间通信中。常见的使用情况包括:
信号通知
: 当异步 I/O 操作完成,内核会向设置的进程或进程组发送信号。这允许应用程序实现更灵活的 I/O 处理机制。进程管理
: 当需要通过文件描述符进行进程间通信时,F_SETOWN 可以指定接收事件的进程,F_GETOWN 获取当前设置的所有者。
2.5.1 F_SETOWN
-
定义:
F_SETOWN
是一个用于设置文件描述符的拥有者的命令。您可以指定一个进程 ID 或进程组 ID,使其成为文件描述符事件的接收者。(设定 SIGIO和 SIGURG 信号的宿主进程的 PID或进程组的组ID。)
-
用法: 同样与 fcntl 函数配合使用,例如:
c
fcntl(fd, F_SETOWN, owner);
其中 owner 是要设置为新的 PID 或 PGID 的值。
- 参数:
参数 owner 普通进程的 PID 时,设置为该进程作为文件描述符的信号接收者。
参数为 0 时,将信号发送给与该文件描述符关联的进程组。
如果 owner 是负数(如 -group_id),则它会成为该组的所有进程的接收者。
2.5.2 F_GETOWN
- 定义:
F_GETOWN
是一个用于获取文件描述符的拥有者的命令。它返回与文件描述符关联的信号接收者的 PID(进程 ID)或 PGID(进程组 ID)。(获得 SIGIO和 SIGURG 信号的宿主进程的 PID或进程组的组ID。)
- 用法: 通常与 fcntl 函数一起使用,例如:
c
int owner = fcntl(fd, F_GETOWN);
其中 fd 是文件描述符。
- 返回值:
如果返回值大于 0,表示它是一个 PID,意味着普通进程在等待该文件描述符的事件。
如果返回值为 0,表示它是一个进程组 ID,表示该进程组的任何一个进程可以接收信号。
如果返回 -1,表示调用失败,您可以通过 errno 获取错误信息。
SIGIO
和SIGURG
这两个信号与其他Linux信号不同,它们必须和某个文件描述符相关联方可使用:
当被关联的文件描述符可读或者可写时,系统将触发
SIGIO
信号当被关联的文件描述符(必须是一个socket)上有带外数据可读时,系统将触发
SIGURG
信号将信号和文件描述符关联的方法,就是使用fcntl函数为目标文件描述符指定宿主进程或者进程组,那么被指定的宿主进程或者进程组将会捕获这两个信号
使用SIGIO时,还需要利用fcntl设置其O_ASYNC标志(异步IO标志)
2.6 处理异步 I/O 操作时的信号通知
F_SETSIG
和 F_GETSIG
是在 Unix 和 Linux 系统中与文件描述符相关的一组控制命令,通常用于处理异步 I/O 操作时的信号通知。这些命令也是通过 fcntl 系统调用实现的,主要用于管理进程和文件描述符之间的信号机制。
这两个命令主要用于管理异步 I/O 操作,特别是在需要在 I/O 操作完成时通知进程进行处理时。常见的使用情况包括:
-
文件描述符的信号通知: 可以为某个非阻塞的文件描述符设置信号,以便在该文件描述符可以进行读写操作时,进程能够接收到相应的信号处理逻辑。
-
提高事件响应能力: 使用这些命令,应用程序可以异步地响应文件描述符的状态变化,而不需要使用轮询来检查可读性或可写性。
2.6.1 F_SETSIG
-
定义: F_SETSIG 命令用于设置与文件描述符关联的信号。当文件描述符准备好 I/O 操作(如可以读取或写入)时,内核将发送指定的信号给拥有该文件描述符的进程。
-
用法: 与 fcntl 函数一起使用,例如:
c
fcntl(fd, F_SETSIG, SIGUSR1);
- 参数:
提供给 F_SETSIG 的参数是一个信号值,可以是任何有效信号(例如 SIGIO、SIGUSR1 等)。
当文件描述符状态变化时,内核将发送此信号给拥有该文件描述符的进程。
2.6.2 F_GETSIG
- 定义: F_GETSIG 命令用于获取与文件描述符关联的当前信号值。
- 用法: 也通过 fcntl 函数使用,例如:
c
int sig = fcntl(fd, F_GETSIG);
这将返回与文件描述符 fd 相关联的当前信号值。
返回值: 返回的信号值表示当前为文件描述符设置的信号。如果没有为该文件描述符设置信号,可能返回无效信号(如 0)。如果调用失败,将返回 -1,并可以通过 errno 获取错误信息。
fcntl函数支持的常用操作以其参数如表所示:
fd对应的文件状态标志: