一、函数介绍
#include <unistd.h>
int dup(int fd);
int dup2(int fd, int fd2);
  • 功能:这两个函数可用来复制一个现有的文件描述符 

 dup()

  • 功能:复制fd所指的文件描述符,返回一个新的文件描述符
  • 自己不能指定新的文件描述符,系统自己分配一个最小的可用的文件描述符
  • fd参数:一个已存在并打开的文件描述符
  • 返回值:
    • 成功:新的文件描述符
    • 失败:返回-1

dup2()

  • 功能:复制fd所指的文件描述符,返回一个新的文件描述符
  • 参数:
    • fd:一个已存在并打开的文件描述符
    • fd2:自己传入的,指定新的文件描述符
  • 使用方法:
    • 如果fd2已经打开,则先将其关闭
    • 如果fd等于fd2,那么dup2函数不执行任何操作,dup2函数返回fd2,而不关闭它
    • 否则fd2的FD_CLOEXEC文件描述符标志就被清除,这样fd2在进程调用exec时是打开状态

数据结构剖析

  • 这两个函数返回的新文件描述符与参数fd共享同一个文件表项
  • 假设我们现在执行下面的代码:
int newfd = dup(1);
  • 当此函数开始执行时,假定下一个可用的描述符是3 (这是非常有可能的,因为 0,1和2由shell打开)。因为两个描述符指向同一文件表项,所以它们共享同一文件状态标志 (读、写、添写等) 以及同一当前文件位移量

APUE编程:15---文件I/O之(文件描述符复制函数:dup()、dup2())_文件描述符

  • 两个函数创建的文件描述符并不继承原文件描述符的属性,比如close-on-exec和non-blocking等。每个文件描述符都有它自己的一套文件描述符标志。正如我们将在下一节中说明的那样, 新描述符的执行时关闭( close-on-exec )文件描述符标志总是由dup函数清除
二、fcntl()函数的复制功能
  • 复制一个描述符的另一种方法是使用fcntl函数
  • fcntl()函数参阅:javascript:void(0)

演示案例

  • 方法一:调用dup(fd);等效于fcntl(fd, F_DUPFD, 0);
  • 方法二:调用dup2(fd, fd2);等效于close(fd2);fcntl(fd, F_DUPFD, fd2);
  • 在方法二中,dup2并不完全等同于close加上fcntl。它们之间的区别是:
    • dup2是一个原子操作,而close及fcntl则包括两个函数调用。有可能在close和fcntl之间调用了信号捕获函数,它可能修改文件描述符。如果不同的线程改变了文件描述符的话也会出现相同的问题
    • 在dup2和fcntl之间有某些不同的errno

APUE编程:15---文件I/O之(文件描述符复制函数:dup()、dup2())_#include_02

三、演示案例
  • 先打开一个描述符fd读取dup.txt5个字节,然后用dup复制一个描述符dup_fd读取5个字节。然后再使用原来的fd再读取5个字节,观察结果
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char *argv[])
{
    int fp;
    if((fp=open("dup.txt",O_RDONLY))==-1){
        perror("open file error");
        exit(EXIT_FAILURE);
    }

    char buf[5];

    memset(buf,'\0',sizeof(buf));
    if((read(fp,buf,5))<=0){
        perror("read file error");
        exit(EXIT_FAILURE);
    }
    printf("now buf data is %s\n",buf);

    int dup_fp=dup(fp);
    memset(buf,'\0',sizeof(buf));
    if((read(dup_fp,buf,5))<=0){
        perror("read file error");
        exit(EXIT_FAILURE);
    }
    printf("now buf data is %s\n",buf);

    memset(buf,'\0',sizeof(buf));
    if((read(fp,buf,5))<=0){
        perror("read file error");
        exit(EXIT_FAILURE);
    }
    printf("now buf data is %s\n",buf);

    close(fp);
    return 0;
}


APUE编程:15---文件I/O之(文件描述符复制函数:dup()、dup2())_文件描述符复制_03

APUE编程:15---文件I/O之(文件描述符复制函数:dup()、dup2())_dup2_04

  • fd与dup_fd使用同一个文件表。文件偏移量等都是相同的
四、演示案例