dup2的函数定义为:

  1. #include <unistd.h>
  2.  
  3. int dup2(int src_fd, int new_fd);

自己实现dup2函数有几个关键点:

1,检查给定的源fd是否有效,且都大于0,

2,检查目标fd是否超出了系统设定的范围,而这个值在书上是没有着重指出的,

  比如mac限制了要小于256,ubuntu限制是1024。

3,源fd与目标fd是否相等,

4,利用系统的特性:dup总是返回最小可用的fd,不断重复dup,从而得到一个等于new_fd的fd值

  再清除掉new_fd之前的临时fd

5,如果在4)的过程中。如果中途dup失败。则需要在返回失败前,关掉这些临时的fd。

  因此close这些临时fd时,需要区别是创建new_fd成功还是失败了。

下面是代码,仅限于类Unix系统环境:

  1. /*
  2. * name : dup2.c
  3. * func : implement of dup2 without fcntl.h
  4. * author : jungle85gopy
  5. * date : 2015.12.20
  6. */
  7.  
  8. /*
  9. * Note :
  10. * man dup() of Mac OSX
  11. * Dup() duplicates an existing object descriptor and returns
  12. * its value to the calling process (fildes2 = dup(fildes)).
  13. * The value must be less than the size of the table, which is returned by
  14. * getdtablesize(2). the size is 256 for Mac OSX 10.11.
  15. * man dup() in ubuntu, there is no info about getdtablesize(2).
  16. * but Ubuntu 14.04 still has getdtablesize limit of 1024.
  17. */
  18.  
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <sys/utsname.h>
  23.  
  24. #define INIT_FD -2
  25.  
  26. int my_dup2(int src_fd, int new_fd);
  27. int chk_dup(int src_fd, int new_fd);
  28. int do_dup2(int src_fd, int new_fd);
  29.  
  30. /*
  31. * usage: dup2 src_fd, new_fd
  32. */
  33. int main(int argc, char *argv[])
  34. {
  35. if (argc != ) {
  36. printf("usage: dup2 src_fd new_fd\n");
  37. exit();
  38. }
  39.  
  40. int new_fd = new_fd = my_dup2(atoi(argv[]), atoi(argv[]) );
  41. if (new_fd == -) {
  42. printf("dup to new_fd error!\n");
  43. exit();
  44. }
  45. printf("\n[main]: new fd is %d\n", new_fd);
  46. return new_fd;
  47. }
  48.  
  49. /*
  50. * func: check the parameter of my_dup2
  51. * return:
  52. * -1: if error
  53. * 0 : if success
  54. */
  55. int chk_dup(int src_fd, int new_fd)
  56. {
  57. int tbl_size = getdtablesize();
  58.  
  59. printf("[my_dup2]: parameter : src fd %d\n", src_fd);
  60. printf("[my_dup2]: parameter : new fd %d\n\n", new_fd);
  61.  
  62. if (src_fd < || new_fd < ) {
  63. printf("[my_dup2]: error: src or des parameter < 0.\n");
  64. return -;
  65. }
  66. else if (new_fd >= tbl_size ) {
  67. printf("[my_dup2]: error: des_fd out of system limit: %d\n", tbl_size);
  68. return -;
  69. }
  70.  
  71. int index;
  72. if ( (index = dup(src_fd)) == -) {
  73. printf("[my_dup2]: parameter src_fd is inactive!\n");
  74. return -;
  75. } else
  76. close(index);
  77.  
  78. return ;
  79. }
  80.  
  81. /*
  82. * func: dup a file descriptor from src_fd to new_fd
  83. * return:
  84. * new_fd if success
  85. * -1 if error
  86. */
  87. int my_dup2(int src_fd, int new_fd)
  88. {
  89. int ret;
  90.  
  91. if ( (ret = chk_dup(src_fd, new_fd)) == -)
  92. return -;
  93. if (src_fd == new_fd)
  94. return src_fd;
  95.  
  96. // close new_fd, whether it is valid or not. ignore the return
  97. close(new_fd);
  98.  
  99. if ( (ret = do_dup2(src_fd, new_fd)) == -) {
  100. printf("[my_dup2]: do dup failed!\n");
  101. return -;
  102. } else
  103. return ret;
  104. }
  105.  
  106. /*
  107. * func: dup from 0 to new_fd
  108. */
  109. int do_dup2(int src_fd, int new_fd)
  110. {
  111. int index, index_hit = -, fd_array[new_fd];
  112.  
  113. for (index = ; index <= new_fd; index++)
  114. fd_array[index] = INIT_FD; // initial to INIT_FD
  115.  
  116. printf("[my_dup2]: before dup temp fds\n");
  117. for (index = ; index <= new_fd; index++) {
  118. fd_array[index] = dup(src_fd);
  119. printf("[my_dup2]: index: %d, create temp fd: %d\n", index, fd_array[index]);
  120.  
  121. if (fd_array[index] == -) {
  122. printf("[my_dup2]: dup process error!\n");
  123. break;
  124. } else if (fd_array[index] == new_fd) {
  125. index_hit = index;
  126. break;
  127. }
  128. }
  129.  
  130. // close temp fd
  131. printf("\n[my_dup2]: to close temp fds\n");
  132.  
  133. if (index_hit == -) { // break for loops with error
  134. for (index = ; index < new_fd; index++) {
  135. if ((fd_array[index] == INIT_FD) || (fd_array[index] == -))
  136. break; // no new temp dup in array
  137. else {
  138. close(fd_array[index]);
  139. printf("[my_dup2]: index: %d, del temp fd: %d\n", index, fd_array[index]);
  140. }
  141. }
  142. return -;
  143. } else { // break for loops with hit
  144. for (index = ; index < index_hit; index++) {
  145. close(fd_array[index]);
  146. printf("[my_dup2]: index: %d, temp fd: %d\n", index, fd_array[index]);
  147. }
  148. }
  149. return new_fd;
  150. }

[APUE]不用fcntl实现dup2函数功能的更多相关文章

  1. UNIX环境高级编程APUE练习3.2-不用fcntl实现dup2的功能

    1 题面 编写与dup2功能相同的函数,要求不调用fcntl函数,并且要有正确的出错处理. 2 基本思路 不能用fcntl,能够返回一个文件描述符的只有open和dup.而open会创建一个新的文件表 ...

  2. 第3章 文件I/O(4)_dup、dup2、fcntl和ioctl函数

    5. 其它I/O系统调用 (1)dup和dup2函数 头文件 #include<unistd.h> 函数 int dup(int oldfd); int dup2(int oldfd, i ...

  3. APUE中fcntl.h的使用及O_SYNC在Mac与Ubuntu下的测试

    此部分测试涉及到APUE V3中,第三章的图3-12到图3-14. 通过fcntl.h提供的功能,修改fd的文件属性,本处增加O_SYNC功能,并测试其效果. 本文涉及代码: tree ch3 ch3 ...

  4. linux之dup和dup2函数解析

    1. 文件描述符在内核中数据结构在具体说dup/dup2之前,我认为有必要先了解一下文件描述符在内核中的形态.一个进程在此存在期间,会有一些文件被打开,从而会返回一些文件描述符,从shell中运行一个 ...

  5. dup和dup2函数

    下面两个函数都可用来复制一个现存的文件描述符: #include<unistd.h> int dup(int filedes); int dup2(int filedes,int file ...

  6. dup和dup2函数以及管道的实现

    疑问:管道应该不是这样实现的,因为这要求修改程序的代码 dup和dup2也是两个非常有用的调用,它们的作用都是用来复制一个文件的描述符.它们经常用来重定向进程的stdin.stdout和stderr. ...

  7. dup,dup2函数【转】

    转自:http://eriol.iteye.com/blog/1180624 转自:http://www.cnblogs.com/jht/archive/2006/04/04/366086.html ...

  8. 2-3 Sass的函数功能-列表函数

    列表函数主要包括一些对列表参数的函数使用,主要包括以下几种: length($list):返回一个列表的长度值: nth($list, $n):返回一个列表中指定的某个标签值 join($list1, ...

  9. Unix 网络编程 dup和dup2函数

    dup和dup2也是两个很实用的调用,它们的作用都是用来复制一个文件的描写叙述符. 它们经经常使用来重定向进程的stdin.stdout和stderr.这两个函数的原形例如以下: #include & ...

随机推荐

  1. 你必须知道的EF知识和经验

    注意:以下内容如果没有特别申明,默认使用的EF6.0版本,code first模式. 推荐MiniProfiler插件 工欲善其事,必先利其器. 我们使用EF和在很大程度提高了开发速度,不过随之带来的 ...

  2. [高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  3. HTML DOM 对象

    本篇主要介绍HTML DOM 对象:Document.Element.Attr.Event等4个对象. 目录 1. Document 对象:表示文档树的根节点,大部分属性和方法都是对元素进行操作. 2 ...

  4. javascript单元测试框架mochajs详解

    关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...

  5. sql的那些事(一)

    一.概述 书写sql是我们程序猿在开发中必不可少的技能,优秀的sql语句,执行起来吊炸天,性能杠杠的.差劲的sql,不仅使查询效率降低,维护起来也十分不便.一切都是为了性能,一切都是为了业务,你觉得你 ...

  6. 缓存、队列(Memcached、redis、RabbitMQ)

    本章内容: Memcached 简介.安装.使用 Python 操作 Memcached 天生支持集群 redis 简介.安装.使用.实例 Python 操作 Redis String.Hash.Li ...

  7. peer not authenticated的终极解决方案

    一.前述 使用httpclient发起https请求时,可能会遇到如下异常: javax.net.ssl.SSLPeerUnverifiedException: peer not authentica ...

  8. java中易错点(二)

    java,exe是java虚拟机 javadoc.exe用来制作java文档 jdb.exe是java的调试器 javaprof,exe是剖析工具 解析一: sleep是线程类(Thread)的方法, ...

  9. Android—Volley:接收服务端发送的json数据乱码问题解决

    new JsonObjectRequest中重写方法parseNetworkResponse,内容如下: /** * 重写此方法不会导致乱码 */ @Override protected Respon ...

  10. grep 查找bash脚本中的注释代码

    出于安全性的考虑,不建议在bash脚本中注释掉不使用的代码.也就是说如果某段代码不使用了,那么应该删除掉,而不是简单地注释掉.假如你突然意识到这一点,而以前并没有遵从这个原则,现在需要找出脚本中的注释 ...