Linux系统编程中fcntl和ioctl的区别是什么?一文详解

 更新时间:2026年09月05日 09:35:50   作者:en.en..  
还在纠结fcntl和ioctl怎么选?本文用最直白的语言讲清两者的区别:fcntl是POSIX标准,适用于所有文件描述符,常用于设置非阻塞IO和复制描述符;ioctl则是设备专属,专治屏幕、串口、网卡等硬件,附带经典代码示例,帮你快速掌握Linux系统编程核心

前言

在 Linux 系统编程中,fcntlioctl 都是用于对文件描述符进行二次控制的系统调用。

二者容易混淆,但分工极其明确:

  • fcntl:POSIX 标准,所有文件描述符通用(文件、管道、socket、设备)

  • ioctl:设备私有接口,只用于硬件设备文件

本文按学习顺序:先 fcntl、后 ioctl,结构清爽、重点突出,适合入门与复习。

一、fcntl 文件描述符通用控制

1. 函数原型与头文件

#include <fcntl.h> 
int fcntl(int fd, int cmd, ...);

2. 参数说明

fd:任意合法文件描述符。 普通文件、无名管道、Socket、设备文件都支持,适用范围极广。

cmd:标准控制命令(POSIX 统一定义),跨平台兼容。

可变参数 ...:由 cmd 决定,绝大多数场景传递整数,少量命令使用结构体。

3. 返回值

  • 成功:根据命令返回对应数值

  • 失败:返回 -1,并自动设置 errno 错误码

4. 最经典使用场景(考试/面试重点)

fcntl 的核心用途:修改文件描述符的标准 IO 属性

  • 无名管道、Socket 设置非阻塞 IO(最常考)

  • 复制文件描述符(F_DUPFD)

  • 设置 FD_CLOEXEC,防止子进程继承句柄泄露

  • 文件区域读写锁,用于多进程文件同步

  • 设置信号驱动 IO(SIGIO)

5. 经典代码示例:管道设置非阻塞

这是 fcntl 最基础、最标准的入门案例:

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

int main(void)
{
    int pipefd[2];
    pipe(pipefd);

    // 获取原有文件状态标志
    int flags = fcntl(pipefd[0], F_GETFL);
    // 设置非阻塞属性
    fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK);

    close(pipefd[0]);
    close(pipefd[1]);
    return 0;
}

二、ioctl 硬件设备专属控制

1. 函数原型与头文件

#include <sys/ioctl.h>

int ioctl(int fd, unsigned long op, ...);

2. 参数说明

fd硬件设备文件描述符(屏幕、串口、网卡、外设等)。普通文件不使用 ioctl。

op:设备控制指令(魔数)。 由设备驱动自定义,不同设备指令完全不通用

可变参数 ...:完全由指令决定。 读取硬件信息必须传结构体指针,不能传结构体变量。

3. 返回值

  • 成功:返回 0

  • 失败:返回 -1,并设置 errno

4. 经典使用场景

ioctl 只干一件事:操作硬件独有功能

  • 屏幕帧缓冲:获取分辨率、色深

  • 终端/串口:波特率、窗口大小、回显模式

  • 网卡:MAC 地址、MTU、网络参数

  • 嵌入式外设:GPIO、声卡、摄像头、磁盘参数

5. 经典代码示例:ioctl 获取屏幕分辨率

需要屏幕结构体头文件:

#include <linux/fb.h>

核心结构体:

struct fb_var_screeninfo {
    __u32 xres;          // 横向分辨率
    __u32 yres;          // 纵向分辨率
    __u32 bits_per_pixel;// 像素色深
};

重点:FBIOGET_VSCREENINFO 必须传入结构体地址指针

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

int main(void)
{
    int fd = open("/dev/fb0", O_RDWR);
    if (fd < 0)
    {
        perror("open fb0");
        return -1;
    }

    struct fb_var_screeninfo info;
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
    {
        perror("ioctl get screen");
        close(fd);
        return -1;
    }

    printf("分辨率:%u × %u\n", info.xres, info.yres);
    printf("色深:%u bpp\n", info.bits_per_pixel);

    close(fd);
    return 0;
}

三、fcntl 与 ioctl 核心区别

1. 适用范围不同

fcntl:所有 fd 通用(文件、管道、socket、设备)

ioctl:仅硬件设备文件专用

2. 标准性、移植性不同

fcntl:POSIX 标准,跨平台通用

ioctl:驱动自定义,不通用、不可移植

3. 经典学习场景不同

fcntl:无名管道设置非阻塞 IO

ioctl:获取屏幕分辨率、硬件信息

4. 传参特点不同

fcntl:大多传整数参数

ioctl:读硬件信息必须传结构体指针

四、最终使用口诀

  • 通用文件属性、管道、socket 配置 → 用 fcntl

  • 屏幕、串口、网卡、硬件设备控制 → 用 ioctl

五、总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 在服务器上启用HTTP公钥固定扩展的教程

    在服务器上启用HTTP公钥固定扩展的教程

    这篇文章主要介绍了在服务器上启用HTTP公钥固定扩展的教程,示例包括对Apache和NGINX以及Lighttpd服务器的演示,需要的朋友可以参考下
    2015-06-06
  • Kali Linux集群搭建实现过程

    Kali Linux集群搭建实现过程

    这篇文章主要介绍了Kali Linux集群搭建实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-03-03
  • 分别在Linux和Windows下设置JVM内存的简单方法

    分别在Linux和Windows下设置JVM内存的简单方法

    下面小编就为大家带来一篇分别在Linux和Windows下设置JVM内存的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Apache James配置连接达梦数据库的步骤

    Apache James配置连接达梦数据库的步骤

    本文介绍了如何配置Apache James邮件服务器以连接达梦数据库,包括导入JDBC驱动、修改配置文件和SQL语句,并提供了解决启动报错的方法
    2024-09-09
  • 实例详解Linux 中的命令链接操作符

    实例详解Linux 中的命令链接操作符

    这篇文章通过实例代码给大家详细介绍了Linux 中的命令链接操作符,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-08-08
  • linux下日志定时轮询的流程详解

    linux下日志定时轮询的流程详解

    这篇文章主要给大家介绍了关于在linux下日志定时轮询流程的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06
  • Linux运维之磁盘分区与挂载详解

    Linux运维之磁盘分区与挂载详解

    磁盘分区是将物理硬盘划分为不同的逻辑部分,每个分区都可以被视为一个独立的存储设备,这篇文章主要介绍了Linux系统中的磁盘分区原理以及如何创建、格式化、临时和永久挂载分区的相关内容,有需要的小伙伴可以了解下
    2025-12-12
  • Linux上使用Docker下载和运行Redis的完整步骤

    Linux上使用Docker下载和运行Redis的完整步骤

    这篇文章主要介绍了Linux上使用Docker下载和运行Redis的完整步骤,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-10-10
  • DDNS 的工作原理及其在 Linux 上的实现

    DDNS 的工作原理及其在 Linux 上的实现

    DDNS (Dynamic DNS) 扩展了 DNS 将客户端 IP 与其域名进行静态映射的功能,它可以将同一域名实时地解析为不同的动态 IP,而不需要额外的人工干预
    2016-09-09
  • 基于Apache Hudi在Google云构建数据湖平台的思路详解

    基于Apache Hudi在Google云构建数据湖平台的思路详解

    这篇文章主要介绍了基于Apache Hudi在Google云构建数据湖平台,本文提供了有关如何使用上述工具构建基本数据管道的基本介绍,需要的朋友可以参考下
    2022-04-04

最新评论