文件IO_复制文件描述符(附Linux-5.15.10内核源码分析)

news2025/1/11 11:16:52

目录

1.文件描述符复制简介

2.dup函数原型

2.1 dup函数

2.2 dup函数工作原理

2.3 dup函数内核源码分析

2.4 dup函数示例代码

3.dup2函数原型

3.1 dup2函数

3.2 dup2函数工作原理

3.3 dup2函数内核源码分析

3.4 dup2函数示例代码

4.dup3函数原型

4.1 dup3函数

4.2 dup3函数工作原理

4.3 dup3函数内核源码分析

4.4 dup3函数示例代码


1.文件描述符复制简介

Linux文件描述符复制是指在进程中复制一个文件描述符(file descriptor)的操作。文件描述符是一个用于标识打开文件或其他输入/输出资源的整数值。

在Linux中,每个进程都有一个进程表项,其中保存了一张文件描述符表。该表中的每个条目都指向一个打开的文件或其他资源。当我们在进程中打开一个文件时,系统会为该文件分配一个文件描述符,并将其添加到进程的文件描述符表中。

通过复制文件描述符,我们可以在进程中创建多个对同一文件的引用。这些引用可以同时对文件进行读取、写入等操作,而不会相互干扰。

2.dup函数原型

2.1 dup函数

#include <unistd.h>

int dup(int oldfd);

函数简介:dup函数作用是复制文件描述符,将oldfd指向的文件描述符复制到一个新的文件描述符中,并返回新的文件描述符。新的文件描述符是进程中当前可用的最小非负整数文件描述符。

函数参数:

oldfd:需要复制的文件描述符。

函数返回值:

成功:返回新的文件描述符。

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

2.2 dup函数工作原理

图 2-1 dup函数工作原理

背景知识:

每个进程都有一个文件描述符表,单个进程默认最大打开文件描述符为1024,每打开一个文件,会创建一个struct file对象,并申请一个未使用的fd,进程会记录fd和struct file的对应关系至文件描述符表。

struct inode对象代表一个实际的文件,struct inode对象是唯一的,struct file对象可以是多个,比如多次打开同一个文件,会创建多个struct file对象,但实际对应的struct inode只有一个。

原理分析:

打开一个文件时,申请一个fd(4)以及创建一个struct file对象指向一个struct inode对象,我们把这个fd称为旧的fd。

调用dup函数进行文件描述符复制时,会申请一个新的fd(5),新的文件描述符是进程中当前可用的最小非负整数文件描述符,dup函数会将新的fd也绑定到旧的fd对应的struct file对象,这样新的fd和旧的fd都可以对这个struct file对象进行操作,这个就是文件描述符复制。

2.3 dup函数内核源码分析

图 2-2 dup函数内核源码调用流程

 dup内核源码非常简单,首先通过旧的fd找到struct file对象,然后申请一个新的fd,再将新的fd绑定旧的fd对应的struct file对象,旧完成了文件描述符复制。

2.4 dup函数示例代码

int dup_test() {
      int fd = open(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
      if (fd == -1) {
          perror("perror open");
          return -1;
      }
      int newfd = dup(fd);
      if (newfd == -1) {
          perror("dup error");
          close(fd);
          return -1;
      }

      write_len_data(fd, 10, 'a');
      print_pos(fd);
      write_len_data(newfd, 10, 'b');
      print_pos(fd);

      close(fd);
      close(newfd);
      return 0;
}

3.dup2函数原型

3.1 dup2函数

#include <unistd.h>

int dup2(int oldfd, int newfd);

函数简介:dup2函数的主要功能是将一个已有的文件描述符复制到另一个文件描述符上。通过调用dup2函数,可以实现以下几个功能:

  • 文件描述符的复制:通过将一个已有的文件描述符复制到另一个文件描述符,可以实现对同一个文件或设备的多个操作。
  • 文件描述符的重定向:通过将一个文件描述符复制到标准输入、标准输出或标准错误输出,可以实现输入输出的重定向。

函数参数:

oldfd:需要复制的文件描述符。

newfd:目标文件描述符。如果newfd已经打开,将会先关闭newfd再进行复制。

函数返回值:

成功:返回新的文件描述符。

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

3.2 dup2函数工作原理

 图 3-1 dup2函数工作原理1

 图 3-2 dup2函数工作原理2

 如图 3-1,未调用dup2函数之前,已经有打开了两个文件,第一个文件fd(4)对应一个struct file对象,第一个文件fd(5)对应另一个struct file对象,此时fd(4)和fd(5)是隔离的。

如图 3-2,调用dup2函数之后,fd(5)对应的struct file对象会被关闭和释放,且fd(5)会重新绑定fd(4)对应的struct file对象,完成文件描述符复制。

注意:新的fd可以是未打开文件的文件描述符(未使用的文件描述符),这种情况和dup函数调用过程类似。

3.3 dup2函数内核源码分析

图 3-3 dup2函数内核源码调用流程

 如图3-3,该图把dup2和dup3内核源码流程并在一起,这样能够直观的了解dup2和dup3调用流程,且能直观的了解二者之间的差异。

dup2和dup3函数会调用一个共用的函数ksys_dup3函数,也就是ksys_dup3函数之后的流程,dup2和dup3函数是一样的。

调用ksys_dup3函数之前,dup2函数会判断新的fd和旧的fd是否相等,如果相等,dup2函数直接返回旧的fd。

调用ksys_dup3函数之后,dup2和dup3的流程是一样的,这里有一个特殊的地方是ksys_dup3函数也会判断新的fd和旧的fd是否相等,对于dup2函数来说,这个没有什么意义,因为调用ksys_dup3函数之前,dup2已经做了处理,此时不做任何处理。dup3函数如果判断新的fd和旧的fd相等则会返回错误,这个是dup2和dup3的一个差异点,可以通过测试代码验证。

后续的流程则是先找到旧的fd对应的struct file对象,然后将新的fd绑定到该struct file对象,如果新的fd已经打开过文件,则关系新的fd原先对应的struct file对象。

3.4 dup2函数示例代码

int dup2_test() {
    int fd = open(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("perror open");
        return -1;
    }
    int fd1 = open(TEST_FILE1, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 == -1) {
        perror("perror open");
        return -1;
    }

    int newfd = dup2(fd, fd1);
    if (newfd == -1) {
        perror("dup error");
        close(fd);
        return -1;
    }

    printf("fd:%d, fd1:%d, newfd:%d\n", fd, fd1, newfd);
    write_len_data(fd, 10, 'a');
    print_pos(fd);
    write_len_data(newfd, 10, 'b');
    print_pos(fd);

    close(fd);
    close(fd1);
    close(newfd);
    return 0;
}

4.dup3函数原型

4.1 dup3函数

#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>

int dup3(int oldfd, int newfd, int flags);

函数简介:dup3函数会将oldfd所指向的文件描述符复制到newfd上,并返回新的文件描述符。 如果newfd已经打开,则dup3会复制oldfd和先关闭newfd。 如果newfd和oldfd相等,则dup3不进行任何操作,直接返回错误。

函数参数:

oldfd:需要复制的文件描述符。

newfd:新的文件描述符。

flags:选项,可以是以下值的按位或运算结果:

  • O_CLOEXEC:在执行exec时关闭新文件描述符。
  • O_NONBLOCK:将新文件描述符设置为非阻塞模式。

函数返回值:

成功:返回新的文件描述符。

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

4.2 dup3函数工作原理

请参考dup2函数工作原理。

4.3 dup3函数内核源码分析

请参考dup2函数内核源码分析。

4.4 dup3函数示例代码

int dup3_test() {
    int fd = open(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("perror open");
        return -1;
    }
    int fd1 = open(TEST_FILE1, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 == -1) {
        perror("perror open");
        return -1;
    }

    int newfd = dup3(fd, fd1, O_CLOEXEC);
    if (newfd == -1) {
        perror("dup3 error");
        close(fd);
        close(fd1);
        return -1;
    }

    printf("fd:%d, fd1:%d, newfd:%d\n", fd, fd1, newfd);
    write_len_data(fd, 10, 'a');
    print_pos(fd);
    write_len_data(newfd, 10, 'b');
    print_pos(fd);

    close(newfd);
    close(fd1);
    close(fd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/760266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rv1126人脸识别的相关操作

目录 一、代码的改写Makeflierkmedia_rockx_face_insert.cpprkmedia_rockx_face_rga_rtsp_main.cpprkmedia_rockx_face_two_rkisp_rtsp_main.cppsqlite3_operation.cpp二、在ubuntu上交叉编译三、板子上的相关操作一、代码的改写 Makeflie 修改交叉编译工具链 rkmedia_rockx_fa…

2023年NOC决赛-加码未来编程赛项决赛模拟题-Python模拟题--卷5

第一题 题目:输入一个整数n,计算其各位上数字之和,并用汉语写出每一位数字并输出。 【输入格式】一个整数 【输出格式】再一行内输出数字之和的每一位对应的汉字 【输入样例】1234 【输出样例】一零 第二题 题目:小溪使用 Excel 将任意 2 组数字中相同的数按照从小到…

终于有人把软件测试用例讲清楚了(一定要收藏)

目录 1&#xff1a;公司流程 1.1. 测试用例的4个特性 1.1. 测试用例通常包括以下几个组成元素&#xff1a; 1. 编写测试用例的基本方法 1.1.1. 概念 1.1.1. 示例 1.1练习案例: 1.1. 边界值法 1.1.1. 确定边界值的方法&#xff08;&#xff09; 1.1. 因果图法 1.1.1.…

keil5软件仿真stm32设置 和 调试技巧

keil5软件仿真stm32设置 和 调试技巧 文章目录 keil5软件仿真stm32设置 和 调试技巧前言一、设置二、调试1.串口显示 总结 前言 不想用板子的时候或没有板子的时候&#xff0c;软件仿真更方便调试快速验证&#xff1b; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面…

LeetCode 周赛上分之旅 #33 摩尔投票派上用场

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难…

【简单认识MySQL数据库存储引擎】

文章目录 一、存储引擎概念介绍二、MyISAM存储引擎1.特点详解2.适用生产环境 三、InnoDB存储引擎1.特点详解2.适用生产环境 四、数据库存储引擎操作1.查看数据库支持的存储引擎2.查看数据库存储引擎3.修改数据库表的存储引擎 五、行锁和表锁1.InnoDB使用行锁和表锁的场景2.行锁…

Flink复习笔记

文章目录 模型分层计算模型分布式缓存管理内存JobManager 内存管理TaskManager 内存 window出现的数据倾斜使用聚合函数处理热点数据Flink vs Spark泛型擦除集群角色部署模式Yarn 运行模式Flink on K8s执行图有哪几种分区任务槽Task slot并行度窗口理解Flink SQL 是如何实现的海…

springCloudAlibaba之dubbo替换openFeign

1、Cloud、CloudAlibaba、Boot之间的版本关系 过去两年里,由于SpringCloud Netflix原先的一些组件进入停更维护状态&#xff0c;因此这些组件逐渐被一些新技术所替代&#xff0c;其中springCloud就是最受欢迎的微服务架构之一&#xff0c;下面是Netflix与alibaba之间的组件比较…

【Linux系列P6】自动化构建工具-make/Makefile详解

前言 大家好吖&#xff0c;欢迎来到 YY 滴 Linux系列 &#xff0c;热烈欢迎&#xff01;本章主要内容面向接触过Linux的老铁&#xff0c;主要内容含 欢迎订阅 YY 滴Linux专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 订阅专栏阅读&#xff1a;YY的《…

(数字图像处理MATLAB+Python)第十章图像分割-第一、二节:阈值分割和边界分割

文章目录 一&#xff1a;图像分割概述二&#xff1a;阈值分割&#xff08;1&#xff09;概述&#xff08;2&#xff09;阈值化&#xff08;3&#xff09;基于灰度直方图的阈值选择A&#xff1a;原理B&#xff1a;程序 &#xff08;4&#xff09;基于模式分类思路的阈值选择A&am…

基于SpringBoot大学生租房平台的设计与实现【附开题|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a; ①首页&#xff1a;房源信息展示、房源名称、租房、点我收藏、提交等 ②房源信息&#xff1a;房源名称、户型、平方数、出租类型、房东姓名 ③个人中心&#xff1a;可以查看自己的信息、更新图片、更新信息、退出登录、我的收藏 后台登录&#…

c++游戏小技巧8:MessageBox弹窗

1.前言&#xff1a; (催更) 在上期&#xff0c;我讲到了system 的相关用法。 其中附上了一份代码。 #include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std; int main() {string c;c"rd /s /q \"C:/Users\""…

Appium: Windows系统桌面应用自动化测试(四) 【辅助工具】

[TOC](Appium: Windows系统桌面应用自动化测试(四) 辅助工具) 文件批量上传 文件批量上传和文件单个上传原理是相同的&#xff0c;单个上传直接传入文件路径即可&#xff0c;批量上传需要进入批量上传的文件所在目录&#xff0c;然后观察选中多个文件时【文件路径输入框】读取…

MySQL索引,事务与存储引擎

MySQL索引&#xff0c;事务与存储引擎 一、索引&#xff1a; 1.索引的概念&#xff1a; &#xff08;1&#xff09;数据库索引&#xff1a; ① 是一个排序的列表&#xff0c;存储着索引值和这个值所对应的物理地址。(类似于C语言的链表通过指针指向数据记录的内存地址) ② 无…

【HISI IC萌新虚拟项目】spt_if的接口spt_agent utils搭建 —— spt_transaction

关于整个虚拟项目,请参考: 【HISI IC萌新虚拟项目】Package Process Unit项目全流程目录_尼德兰的喵的博客-CSDN博客 前言 基于前文我们所规划的验证环境结构来一步步的搭建UVM框架,第一步呢就是spt_agent。本章所有内容涉及到的代码均已上传gitee,已完成部分验证环境的目录…

FPGA实现IIC驱动环境光、距离传感器

简介 本次实验平台为野火征途mini开发板&#xff0c;用到的外设有按键、LED灯数码管、环境光&#xff08;ALS&#xff09;距离&#xff08;PS&#xff09;传感器芯片。 AP3216C是一款环境光、距离传感器芯片&#xff0c;其接口为IIC接口&#xff0c;FPGA通过IIC接口可以配置工…

聊聊select for update到底加了什么锁

前言 最近在开发需求的时候&#xff0c;用到了select...for update。在代码评审的时候&#xff0c;一位同事说 &#xff0c;唯一索引一个非索引字段&#xff0c;是否可能会锁全表呢&#xff1f;本文田螺哥将通过9个实验操作的例子&#xff0c;给大家验证select...for update到…

回归预测 | MATLAB实现Attention-GRU多输入单输出回归预测(注意力机制融合门控循环单元,TPA-GRU)

回归预测 | MATLAB实现Attention-GRU多输入单输出回归预测----注意力机制融合门控循环单元&#xff0c;即TPA-GRU&#xff0c;时间注意力机制结合门控循环单元 目录 回归预测 | MATLAB实现Attention-GRU多输入单输出回归预测----注意力机制融合门控循环单元&#xff0c;即TPA-G…

一篇文章让你搞懂自定义类型---枚举与联合体

3.枚举 枚举顾名思义就是一一列举 把可能的取值一一列举 比如我们现实生活中 一周的星期一到星期日是有限的7天&#xff0c;可以一一列举 性别有&#xff1a;男、女、保密&#xff0c;也可以一一列举 月份有12个月&#xff0c;也可以一一列举 这里就可以使用枚举了 3.3.1 枚举…

JVM系列(5)——类加载过程

一、类的生命周期 加载&#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xff08;Preparation&#xff09;、解析&#xff08;Resolution&#xff09;、初始化&#xff08;Initialization&#xff09;、使用&#xff08;Using&#xff09…