当前位置:   article > 正文

【linuxC语言】fcntl和ioctl函数

【linuxC语言】fcntl和ioctl函数


前言

Linux系统编程中,经常会涉及到对文件描述符、套接字以及设备的控制操作。fcntl和ioctl函数就是用来进行这些控制操作的两个重要的系统调用。它们提供了对文件、设备和套接字进行各种操作的接口,为开发者提供了强大的功能,使得他们能够更灵活地控制和管理系统资源。


一、功能介绍

fcntlioctl函数都是用于在Unix/Linux系统中进行对设备、文件描述符或套接字的控制的系统调用。它们的作用是相似的,但用法和适用场景略有不同。

fcntl函数
fcntl函数提供了对文件描述符的各种操作,包括:

复制文件描述符(F_DUPFD):复制一个文件描述符,使得两个文件描述符指向同一个文件表项。
获取/设置文件描述符标志(F_GETFD/F_SETFD):获取或设置文件描述符的标志,例如关闭FD_CLOEXEC标志,使得在exec调用中不关闭文件描述符。
获取/设置文件状态标志(F_GETFL/F_SETFL):获取或设置文件的状态标志,例如非阻塞标志、追加标志等。
获取/设置异步I/O所有权(F_GETOWN/F_SETOWN):获取或设置接收异步I/O事件的进程ID或进程组ID。
取消文件锁(F_SETLK):尝试对文件进行加锁或解锁。
获取/设置记录锁(F_GETLK):获取指定的记录锁信息。

ioctl函数
ioctl函数用于执行设备特定的操作,通常用于与设备驱动程序通信。它的常见用法包括:

设备IO控制:用于对设备进行各种控制操作,如读取设备状态、配置设备参数等。
套接字控制:对套接字进行控制,如获取套接字选项、设置套接字选项等。
文件系统控制:在文件系统上执行特定的控制操作,如获取文件系统信息、设置文件系统参数等。
其他:一些特定的设备或文件系统可能定义了更多的ioctl命令,用于执行特定的操作。

二、具体使用

2.1 fcntl函数

函数原型:

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );
  • 1
  • 2
  • 3

参数:

fd:文件描述符,对应要进行操作的文件或套接字。
cmd:操作命令,指定要执行的操作类型。
arg:可选参数,用于某些操作命令的参数。

返回值的作用:

对于不同的命令,返回值的含义可能不同。一般情况下:
成功:返回值依赖于命令执行的具体情况,可能是一个数值或标志。
失败:返回值为-1,并设置errno以指示错误原因。

示例代码:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main() {
    int fd = open("example.txt", O_RDONLY); // 打开文件
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 获取文件状态标志
    int flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        close(fd);
        return 1;
    }

    // 设置文件状态标志为非阻塞模式
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl F_SETFL");
        close(fd);
        return 1;
    }

    // 其他操作...

    close(fd);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

在这里插入图片描述

2.2 ioctl函数

函数原型:

#include <sys/ioctl.h>

int ioctl(int fd, unsigned long request, ... /* arg */ );
  • 1
  • 2
  • 3

参数:

fd:文件描述符,对应要进行操作的设备或套接字。
request:控制命令,指定要执行的控制操作类型。
arg:可选参数,用于某些控制命令的参数。

返回值的作用:

对于不同的命令,返回值的含义可能不同。一般情况下:
成功:返回值依赖于命令执行的具体情况,可能是一个数值或标志。
失败:返回值为-1,并设置errno以指示错误原因。
示例代码:

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

int main() {
    int fd = open("/dev/mydevice", O_RDWR); // 打开设备文件
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 执行特定的设备控制命令
    int value;
    if (ioctl(fd, MY_DEVICE_IOCTL_COMMAND, &value) == -1) {
        perror("ioctl");
        close(fd);
        return 1;
    }

    // 其他操作...

    close(fd);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

注意:示例中的MY_DEVICE_IOCTL_COMMAND是一个自定义的设备控制命令,你需要根据实际情况替换成你的设备所支持的控制命令。

ioctl函数的控制命令通常被定义在特定的头文件中,这些头文件通常是设备驱动程序的头文件或系统调用的头文件。以下是一些常见的ioctl控制命令示例:

设备IO控制命令:用于对设备进行各种控制操作。
TIOCGWINSZ:获取终端窗口大小。
TIOCSWINSZ:设置终端窗口大小。
FIONBIO:设置/清除非阻塞IO标志。
FIOASYNC:启用/禁用异步IO模式。
TIOCNOTTY:取消控制终端。
TIOCSCTTY:设置控制终端。
TIOCGPGRP:获取前台进程组ID。
TIOCSPGRP:设置前台进程组ID。
套接字控制命令:对套接字进行控制。
SIOCGIFADDR:获取接口的IP地址。
SIOCSIFADDR:设置接口的IP地址。
SIOCGIFNETMASK:获取接口的子网掩码。
SIOCSIFNETMASK:设置接口的子网掩码。
SIOCGIFMTU:获取接口的最大传输单元。
SIOCSIFMTU:设置接口的最大传输单元。
SIOCGIFHWADDR:获取接口的硬件地址。
SIOCSIFHWADDR:设置接口的硬件地址。
文件系统控制命令:在文件系统上执行特定的控制操作。
FS_IOC_GETFLAGS:获取文件系统标志。
FS_IOC_SETFLAGS:设置文件系统标志。
FS_IOC_GETVERSION:获取文件系统版本。
FS_IOC_SETVERSION:设置文件系统版本。
其他命令:一些特定的设备或文件系统可能定义了更多的ioctl命令。
HDIO_GETGEO:获取磁盘几何信息。
HDIO_GET_IDENTITY:获取磁盘的身份信息。
CDROM_GET_CAPABILITY:获取光盘驱动器的功能信息。
CDROM_PLAYTRKIND:播放CD中的某一首曲目。
这只是一小部分常见的ioctl命令,实际上每个设备、文件系统或系统调用都可能定义了自己独特的ioctl命令集合。要查看特定设备或文件系统的ioctl命令,你需要查阅相应的文档或头文件。

三、拓展:填写arg

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

// 假设设备的控制命令为MY_IOCTL_COMMAND
#define MY_IOCTL_COMMAND 0x12345678

int main() {
    // 打开文件
    int fd = open("example.txt", O_RDWR);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 使用fcntl设置文件描述符标志为非阻塞模式
    int flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        close(fd);
        return 1;
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl F_SETFL");
        close(fd);
        return 1;
    }

    // 使用ioctl执行设备控制命令
    int value = 42;
    if (ioctl(fd, MY_IOCTL_COMMAND, &value) == -1) {
        perror("ioctl");
        close(fd);
        return 1;
    }

    // 其他操作...

    close(fd);
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

在这里插入图片描述


总结

通过本文的介绍,我们对fcntl和ioctl函数有了更深入的了解。fcntl函数主要用于对文件描述符的各种操作,包括获取/设置文件状态标志、获取/设置异步I/O所有权、获取/设置文件描述符标志等;而ioctl函数则主要用于执行设备特定的操作,如设备IO控制、套接字控制以及文件系统控制等。这两个函数为Linux系统编程提供了强大的功能和灵活性,使得开发者能够更好地控制和管理系统资源,实现各种复杂的功能。对于想要深入学习Linux系统编程的开发者来说,深入理解和掌握fcntl和ioctl函数是至关重要的一步。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/518885
推荐阅读
相关标签
  

闽ICP备14008679号