Unix/Linux编程:fcntl函数总结

目录

  • 前言
  • [一、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.2 获取/设置文件描述符标志](#2.2 获取/设置文件描述符标志)
      • [2.2.1 `F_GETFD`](#2.2.1 F_GETFD)
      • [2.2.2 `F_SETFD`](#2.2.2 F_SETFD)
    • [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.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.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.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)
  • 三、参考链接

前言

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: 控制命令,指示要执行的操作类型。常见的命令包括:
  1. 复制一个现有的描述符:
    F_DUPFD :.复制文件描述符
    F_DUPFD_CLOEXEC:复制文件描述符,设置FD_CLOEXEC标志
  2. 获得/设置文件状态标记:
    F_GETFL: 获取文件描述符的当前状态标志。
    F_SETFL: 设置文件描述符的状态标志。
  3. 获得/设置文件描述符标记:
    F_GETFD: 获取文件描述符的内部标志。
    F_SETFD: 设置文件描述符的内部标志。
  4. 获得/设置异步I/O所有权:
    F_GETOWN:获得异步I/O所有权
    F_SETOWN:设置异步I/O所有权
  5. 获得/设置记录锁:
    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 二者对比

dupF_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_GETFLF_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_GETLKF_SETLKF_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_whencel_startl_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_GETOWNF_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 获取错误信息。

SIGIOSIGURG这两个信号与其他Linux信号不同,它们必须和某个文件描述符相关联方可使用:

当被关联的文件描述符可读或者可写时,系统将触发SIGIO信号

当被关联的文件描述符(必须是一个socket)上有带外数据可读时,系统将触发SIGURG信号

将信号和文件描述符关联的方法,就是使用fcntl函数为目标文件描述符指定宿主进程或者进程组,那么被指定的宿主进程或者进程组将会捕获这两个信号

使用SIGIO时,还需要利用fcntl设置其O_ASYNC标志(异步IO标志)


2.6 处理异步 I/O 操作时的信号通知

F_SETSIGF_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对应的文件状态标志:


三、参考链接

Unix/Linux编程:fcntl函数总结
Linux fcntl函数详解

相关推荐
入眼皆含月2 分钟前
《Linux基础优化与常用软件包》
linux·运维·服务器
_清风来叙1 小时前
【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题
linux·arm开发·ubuntu
学Linux的语莫1 小时前
k8s中,一.pod污点,二.pod容器污点容忍策略,三.pod优先级(PriorityClass类)
linux·docker·容器·kubernetes
m0_748249541 小时前
Linux环境下Tomcat的安装与配置详细指南
linux·运维·tomcat
随缘与奇迹1 小时前
linux中,软硬链接的作用和使用
linux·运维·服务器
m0_748255651 小时前
Linux环境下的事件驱动力量:探索Libevent的高性能IO架构
linux·架构·php
努力成为DBA的小王2 小时前
Oracle(windows安装遇到的ORA-12545、ORA-12154、ORA-12541、ORA-12514等问题)
linux·运维·服务器·数据库·oracle
DA02212 小时前
CentOS 7.9-2207更换实时内核
linux·运维·centos
Channing Lewis3 小时前
Linux 中为什么进程是休眠的,但是还是处理了数据
linux·运维·服务器
深度Linux3 小时前
Linux性能优化实战,网络丢包问题分析
linux·性能优化·linux内核