Unix环境高级编程学习笔记——dup
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验证代码:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<fcntl.h> 6 #include<errno.h> 7 8 9 #define BUFSIZE 4096 10 11 int main(void) 12 { 13 int fd; 14 int fd2,n; 15 char buf[BUFSIZE]; 16 17 fd = dup(STDIN_FILENO); 18 if(fd < 0) 19 { 20 fprintf(stderr,"dup:%s\n",strerror(errno)); 21 exit(1); 22 } 23 fd2 = dup2(fd,1); 24 if(fd2<0) 25 { 26 fprintf(stderr,"dup2:%s\n",strerror(errno)); 27 exit(0); 28 } 29 30 printf("fd = %d \n",fd); 31 printf("fd2 = %d \n",fd2); 32 33 if((n =read(fd,buf,BUFSIZE)) < 0) 34 { 35 fprintf(stderr,"read:%s\n",strerror(errno)); 36 exit(0); 37 } 38 39 if(write(fd2,buf,n) != n) 40 { 41 fprintf(stderr,"write:%s\n",strerror(errno)); 42 exit(0); 43 } 44 45 46 47 close(fd); 48 close(fd2); 49 return 0; 50 }
结果截图:
My_dup2
要求: 要实现自己写一个dup2,不使用fcntl函数,有正确的错误提示。
分析: 不使用fcntl函数,那就只有使用dup来实现这个dup2了。我们的目的就是让自己所定义的描述符能过符合要求,系统有个要求,最大的描述符不能超过63,也就是最多打开64个描述符,这是第一个要检查的。继而我们检查,这个所定义的描 述符,和我要复制的这个描述符是不是相等的,要是相等的话,那就直接返回了。这是第二个要检查的。好了,这些都符合要求,那么我们就定义一个额外的文件描述符(区别于你给定的文件描述符)。我们用这个额外的一个描述符来接受我们对 我们要复制的描述符的dup的返回值。将这个返回值和你所给定的比对,如果相等就将这个fd返回,说明已经将其复制好。也就完成了dup2的工作了。 解释一下为什么要这么做: dup的返回值是系统中最小的可用的文件描述符,所以我们不能 够一下子就能确定dup返回的这个文件描述符就是你所指定的,同时dup操作也是在将你说指定文件描述符指向你所要复制的那个文件描述符指向的文件状态标志上去(实际上不是,实际上同过dup不断打开的文件描述符,将在你所指定的文件描 述符前的文件描述符占用掉,被迫你的返回你所指定的文件描述符。所以我们要将这些之前不是我们所需的文件描述符保存到一个数组中,待最后找到指定的描述符后就将一一释放掉。)
下面的一个给出可行的代码:
1 /************************************************************************************************************ 2 *程序目的是通过dup实现dup2,并用通过dup2所返回的文件描述符实现文件的写操作 3 *************************************************************************************************************/ 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<string.h> 7 #include<unistd.h> 8 #include<fcntl.h> 9 #include<errno.h> 10 11 //系统在fcntl这个头文件里应该有OPEN_MAX这个参数的,不过我的系统上引入头文件也是没用的 12 //故用条件编译的原理让其自动判断并定义 13 #ifndef OPEN_MAX 14 #define OPEN_MAX 256 15 #endif 16 17 char buf1[] = "abcdefg"; 18 char buf2[] = "ABCDEFG"; 19 20 int mydup2(int ,int); 21 22 int main() 23 { 24 int fd,fd2; 25 26 fd = open("a.txt",O_RDWR|O_CREAT,0644); 27 if(fd < 0) 28 { 29 fprintf(stderr, "open:%s\n",strerror(errno)); 30 exit(0); 31 } 32 33 if(write(fd,buf1,strlen(buf1)) != strlen(buf1)) 34 { 35 fprintf(stderr,"write:%s\n",strerror(errno)); 36 exit(0); 37 } 38 //实现文件描述符的复制 39 fd2 = mydup2(fd,6); 40 41 if(write(fd2,buf2,strlen(buf2)) != strlen(buf2)) 42 { 43 fprintf(stderr,"write2:%s\n",strerror(errno)); 44 exit(0); 45 } 46 47 printf("fd2:%d\n",fd2); 48 49 return 0; 50 51 } 52 53 int mydup2(int filedes,int filedes2) 54 { 55 int fd[OPEN_MAX]; 56 int i =-1; 57 int tfd; 58 //检查你指定的文件描述符是否合法 59 if(filedes < 0 || filedes2 < 0 || filedes2 > OPEN_MAX) 60 { 61 printf("filedes is error!\n"); 62 exit(0); 63 } 64 65 if(filedes == filedes2) 66 { 67 return filedes2; 68 } 69 close(filedes2); 70 //这边是遍历寻找你所指定的文件描述符 71 tfd = dup(filedes); 72 while(filedes2 != tfd) 73 { 74 i++; 75 fd[i] = tfd; 76 tfd = dup(filedes); 77 } 78 //释放之前打开的没有用的文件描述符 79 while(i>=0) 80 { 81 close(fd[i]); 82 i--; 83 } 84 return filedes2; 85 }
运行结果:
上述也就是对dup和dup2的一些理解。谷歌了半天发现这类的资料写的都比较官方,自己看不大懂,自己写下自己的一些理解,也是算是自己的一个学习的验证了。