dup 和 dup2
    dup和dup2,都是用来将一个文件描述符复制给另一个文件描述符上,这两个文件描述符都指向同一个文件状态标志上。
  只是文件描述符的大小不一样,dup所执行下的复制,肯定是返回的系统中最小的可用文件描述符。而dup2.可以自定义文件描述符的。系统的0、1、2描
  述符已经被占用。所以用dup所复制的描述符是不能是这三个的。我们可以将这三个复制给其他的文件描述符。

函数描述

  int dup(int filedes)

  int dup2(int filedes, int filedes2)

dup

   dup的参数是filedes,这个指的是系统中已经打开的文件描述符.返回的确实一个可用的最小文件描述符。

  利用fcntl,我们可以将其分解看:fcntl(filedes ,F_DUPFD,0)

   可以很简单的看一下这三个参数,第一是我们要复制的文件描述符,第二个是fcntl的状态标志,指的是dup一个文件描述符。第三个参数,我们很容易理解错,这边写的是0,有可能你会认为是将0号描述符给返回出去,其实不是,他的是意思 是,返   回一个比这个数大或是等于他的最小描述符。这个和dup的功能解释是符合的。

dup2

  他的参数是有俩,filedes和前面的一样,是我们要复制的文件描述符,后面的filedes2,则是我们想要函数返回的文件描述符,很好理解。

   同样这fcntl中我们可以很清晰的看出:fcntl(filedes, F_DUPFD,filedes2).

  先前的“0”,被我们用filedes2直接替代了。函数返回的就是我们设置的那个filedes2。

confuse

  dup2,对于这个函数,我们可以自己定义文件描述符,这就有一个容易混淆的地方,如果我们将fd定义为从STDIN_FILENO复制过来的,现在我们用fd2 = dup2(fd,1)。我们知道文件描述符1已经是被标准输出占用了,你会说我们现在是在将标准输入   复制给“标准输出”,先不想这个!按照原先的思路现在我们用的fd2应该就是一个标准输入,我们可以拿他来从屏幕上读一个串数据,然后显示到终端上,这个是可以做到的。但是你会说这个fd2不是被赋予了1的描述符吗?怎么可以用作标准输入    呢?回到dup2的定义,dup2在执行的过程中,会看这个filedes2是不是已经打开? 如果打开了,就将其关闭。然后再执行复制,也就是说,这边的fd2就是指向的标准输入了。一个描述符只能指向一个文件状态标志的。所以这个是不冲突的。而标  准输入已经被关闭了。下面是这个confuse验证代码:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h> #define BUFSIZE 4096 int main(void)
{
int fd;
int fd2,n;
char buf[BUFSIZE]; fd = dup(STDIN_FILENO);
if(fd < )
{
fprintf(stderr,"dup:%s\n",strerror(errno));
exit();
}
fd2 = dup2(fd,);
if(fd2<)
{
fprintf(stderr,"dup2:%s\n",strerror(errno));
exit();
} printf("fd = %d \n",fd);
printf("fd2 = %d \n",fd2); if((n =read(fd,buf,BUFSIZE)) < )
{
fprintf(stderr,"read:%s\n",strerror(errno));
exit();
} if(write(fd2,buf,n) != n)
{
fprintf(stderr,"write:%s\n",strerror(errno));
exit();
} close(fd);
close(fd2);
return ;
}

结果截图:

My_dup2

  要求: 要实现自己写一个dup2,不使用fcntl函数,有正确的错误提示。

  分析: 不使用fcntl函数,那就只有使用dup来实现这个dup2了。我们的目的就是让自己所定义的描述符能过符合要求,系统有个要求,最大的描述符不能超过63,也就是最多打开64个描述符,这是第一个要检查的。继而我们检查,这个所定义的描    述符,和我要复制的这个描述符是不是相等的,要是相等的话,那就直接返回了。这是第二个要检查的。好了,这些都符合要求,那么我们就定义一个额外的文件描述符(区别于你给定的文件描述符)。我们用这个额外的一个描述符来接受我们对    我们要复制的描述符的dup的返回值。将这个返回值和你所给定的比对,如果相等就将这个fd返回,说明已经将其复制好。也就完成了dup2的工作了。 解释一下为什么要这么做: dup的返回值是系统中最小的可用的文件描述符,所以我们不能    够一下子就能确定dup返回的这个文件描述符就是你所指定的,同时dup操作也是在将你说指定文件描述符指向你所要复制的那个文件描述符指向的文件状态标志上去(实际上不是,实际上同过dup不断打开的文件描述符,将在你所指定的文件描    述符前的文件描述符占用掉,被迫你的返回你所指定的文件描述符。所以我们要将这些之前不是我们所需的文件描述符保存到一个数组中,待最后找到指定的描述符后就将一一释放掉。)

下面的一个给出可行的代码:

 /************************************************************************************************************
*程序目的是通过dup实现dup2,并用通过dup2所返回的文件描述符实现文件的写操作
*************************************************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h> //系统在fcntl这个头文件里应该有OPEN_MAX这个参数的,不过我的系统上引入头文件也是没用的
//故用条件编译的原理让其自动判断并定义
#ifndef OPEN_MAX
#define OPEN_MAX 256
#endif char buf1[] = "abcdefg";
char buf2[] = "ABCDEFG"; int mydup2(int ,int); int main()
{
int fd,fd2; fd = open("a.txt",O_RDWR|O_CREAT,);
if(fd < )
{
fprintf(stderr, "open:%s\n",strerror(errno));
exit();
} if(write(fd,buf1,strlen(buf1)) != strlen(buf1))
{
fprintf(stderr,"write:%s\n",strerror(errno));
exit();
}
//实现文件描述符的复制
fd2 = mydup2(fd,); if(write(fd2,buf2,strlen(buf2)) != strlen(buf2))
{
fprintf(stderr,"write2:%s\n",strerror(errno));
exit();
} printf("fd2:%d\n",fd2); return ; } int mydup2(int filedes,int filedes2)
{
int fd[OPEN_MAX];
int i =-;
int tfd;
//检查你指定的文件描述符是否合法
if(filedes < || filedes2 < || filedes2 > OPEN_MAX)
{
printf("filedes is error!\n");
exit();
} if(filedes == filedes2)
{
return filedes2;
}
close(filedes2);
//这边是遍历寻找你所指定的文件描述符
tfd = dup(filedes);
while(filedes2 != tfd)
{
i++;
fd[i] = tfd;
tfd = dup(filedes);
}
//释放之前打开的没有用的文件描述符
while(i>=)
{
close(fd[i]);
i--;
}
return filedes2;
}

运行结果:

上述也就是对dup和dup2的一些理解。谷歌了半天发现这类的资料写的都比较官方,自己看不大懂,自己写下自己的一些理解,也是算是自己的一个学习的验证了。

Unix环境高级编程学习笔记——dup的更多相关文章

  1. Unix环境高级编程学习笔记——fcntl

    写这篇文正主要是为了介绍下fcntl,并将我自己在学习过程中的一些理解写下来,不一定那么官方,也有错误,希望指正,共同进步- fcntl: 一个修改一打开文件的性质的函数.基本的格式是 int fcn ...

  2. UNIX环境高级编程学习笔记(十)为何 fork 函数会有两个不同的返回值【转】

    转自:http://blog.csdn.net/fool_duck/article/details/46917377 以下是基于 linux 0.11 内核的说明. 在init/main.c第138行 ...

  3. [置顶] 文件和目录(二)--unix环境高级编程读书笔记

    在linux中,文件的相关信息都记录在stat这个结构体中,文件长度是记录在stat的st_size成员中.对于普通文件,其长度可以为0,目录的长度一般为1024的倍数,这与linux文件系统中blo ...

  4. unix环境高级编程-读书笔记与习题解答-第一篇

    从这周开始逐渐的进入学习状态,每天晚上都会坚持写c程序,并且伴随对这本书的深入,希望能写出更高质量的读书笔记和程序. 本书的第一章,介绍了一些关于unix的基础知识,在这里我不想去讨论linux到底是 ...

  5. 《UNIX环境高级编程》笔记--UNIX标准化及实现

    1.UNIX标准化 1.1.ISO C 1989 年后期,C程序设计语言的ANSI(American National Standards Institute) 标准X3. 15 9-1989得到批准 ...

  6. 《UNIX环境高级编程》笔记——3.文件IO

    一.引言 说明几个I/O函数:open.read.write.lseek和close,这些函数都是不带缓冲(不带缓冲,只调用内核的一个系统调用),这些函数不输入ISO C,是POSIX的一部分: 多进 ...

  7. 《UNIX环境高级编程》笔记——2.标准和实现

    随着UNIX各种衍生版本不断发展壮大,标准化工作就十分必要.其实干啥事都是这样,玩的人多了,必须进行标准化. 一.UNIX标准 1.1 ISO C(ANSI C) ANSI:Amerocan Nato ...

  8. 《UNIX环境高级编程》笔记——1.UNIX基础知识

    这一章节侧重一些基本概念和书中用到的一些名词. 一.引言 所有的操作都提供服务,典型的服务包括:执行新程序.打开文件.读写文件.分配存储区以及获得当前时间等. 二.UNIX体系结构 其实linux常见 ...

  9. unix 环境高级编程 读书笔记与习题解答第四篇

    第一章 第六节 第一小节 这一章没有程序设计和API方面的深入学习,而是注重介绍了unix操作系统中的原始数据类型和系统原型函数,错误处理方面的知识. ____unistd.h____ 该文件包含了u ...

随机推荐

  1. storm核心组件

    Storm核心组件 了解 Storm 的核心组件对于理解 Storm 原理非常重要,下面介绍 Storm 的整体,然后介绍 Storm 的核心. Storm 集群由一个主节点和多个工作节点组成.主节点 ...

  2. XXX 用户 is not in the sudoers file. This incident will be reported 的问题解决方案

    说的是,这种问题,是出现在ubuntu系统里. root@SparkSingleNode:/usr/local/jdk# pwd /usr/local/jdk root@SparkSingleNode ...

  3. A Tour of Go For continued

    As in C or Java, you can leave the pre and post statements empty. package main import "fmt" ...

  4. javascript中bind,apply,call的相同和不同之处

    javasctipt中bind,apply,call的相同点是: 1,都是用来改变this的指向; 2,都可以通过后续参数进行传参; 3,第一个参数都是指定this要指向的对象; 不同点: 1,调用方 ...

  5. AtomicLong

    Spring package com.uniubi.management.controller; import java.util.concurrent.atomic.AtomicLong; impo ...

  6. ConversionException: No value specified for 'Date'的解决版本

    DateConverter converter = new DateConverter(defaultValue); ConvertUtils.register(converter, java.uti ...

  7. Hyper-V介绍

    Hyer-v主机是高端虚拟主机用户的最佳选择.您不再受其他用户程序对您造成的影响,您将得到的是更加公平的资源分配,远远低于虚拟主机的故障率.Hyper-V的分区包含两种:父分区和客户分区.Hyper- ...

  8. Spring3.0官网文档学习笔记(八)--3.4.3~3.4.6

    3.4.3 使用depends-on     使用depends-on能够强制使一个或多个beans先初始化,之后再对这个bean进行初始化. 多个bean之间用","." ...

  9. 15 Linux Split and Join Command Examples to Manage Large Files--reference

    by HIMANSHU ARORA on OCTOBER 16, 2012 http://www.thegeekstuff.com/2012/10/15-linux-split-and-join-co ...

  10. redis持久化(摘录)

    redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化.redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Ap ...