APUE 第三章习题 3.2 浅析

题目描述:编写一个与3.12节中dup2功能相同的函数,要求不能调用fcntl函数,并且有正确的出错处理。

题目分析:既然不能使用fcntl函数,那么我们就需要使用其他函数来达到类似的目的,这里列举出所有我们需要使用的函数。

1、  open函数:这里我们不应该指定一个文件描述符并尝试复制它,因为实际中我们不能知道我们指定的文件描述符就一定是合法的,这个文件描述符可能未被使用,如果这样的话就会导致后面一系列的操作失败。或者是这个文件描述符指向了一个已经打开,而且对用户非常重要的文件(操作不当的后果可想而知)。所以用open函数打开一个已经存在的文件是非常靠谱的,我们就可以复制open函数返回的文件描述符。当然,我们还要注意open函数调用时可能产生的错误进行处理。

2、  dup函数:在不能使用fcntl函数的情况下,dup函数是唯一的选择。注意dup函数的返回值,如果操作成功时返回可用的最小的文件描述符,出错时返回-1。当然,dup函数出错也是有可能的,比如说系统资源问题,或者是文件描述符用光(就现在的UNIX Like来说貌似不大可能,但是还是建议考虑一下)。

3、  输出函数:你需要将一些错误的信息输出到屏幕,告诉用户相关的错信息。

4、  close函数:用来关闭一个文件描述符,如果我们指定了将文件描述符a复制为b,如果文件描述符b被占用了,那么我们应该立即关闭它。

5、  atoi函数:将字符串转成数字,这个函数有可能会用到,具体需要看程序是如何实现的。

思路与实现细节:

         首先我们应该用open函数打开一个文件,并获取open函数返回的文件描述符,我们假定open函数获取的文件描述符为”file_flag”,要复制成的指定文件描述符为”obj_flag”。我们要考虑下面的一些问题,比如说打开文件操作失败,文件访问权限问题或者文件不存在都会导致该问题。当然,这似乎不应该是这个程序需要重点处理的问题,我们只需要返回一个适当的错误信息就可以了,不必去进行创建文件的操作。想一想,一个程序在悄无声息的就创建了一个用户以为存在(实际原来不存在)的文件而且还对其进行了操作。当然用户可能认为这些过程都是正确的(比如那个文件原来就存在),后果有可能是难以预测的。另外,通过open函数获取的文件描述符(file_flag)很可能与你指定要复制成的文件描述符(obj_flag)相同!这就涉及到了下一个问题,我们指定的文件描述符是否合法。

         指定的文件描述符不应该占用0~2这三个文件描述符,而且不能超过一个系统允许的上限,即OPEN_MAX,不过有些UNIX Like对其没有限制,但是建议指定的文件描述符(obj_flag)不要过大。如果指定的文件描述符与open函数获取的文件描述符相同当然也是不行的。如果出现文件描述符上述三种问题,应该返回错误,或者干脆让用户重新指定文件描述符。

         实现dup2函数的方式并不难,我们先要保证文件描述符3到obj_flag都被占满,这个只需要不断地调用函数:”dup(file_flag)”,直到其返回的文件描述符值不小于obj_flag。同时需要将这些通过dup函数得到的文件描述符记录下来,以便于以后的释放。之后我们调用函数”close(obj_flag)”,这样就保证了小于obj_flag的所有文件描述符都被占用,而文件描述符obj_flag是可用的。接下来调用”dup(file_flag)”就可以保证了返回的文件描述值为obj_flag(为严谨起见我们还是应该对此时dup函数的返回值进行判断)。如此就实现了与dup2函数相似的功能,但是不要忘记释放那些额外占用的文件描述符,我们需要及时的将其释放。否则如果该程序进程为关闭,就可能在某些UNIX Like系统上造成文件描述符不够用的情况。使用dup函数时,我们也要考虑是否可能存在着dup函数返回一个错误的情况,这时返回一个错误并输出一些相关的警告应该就可以OK了。

         这道题的思路大致如此。当然,即使是上面所有情况都考虑到了这个实现也没有足够好。因为这毕竟不是一个原子操作,如果有另外的一个进程对打开文件操作的话,上面思路实现的代码可靠性仍然没有保证。

代码参考:

#include <apue.h>

#include <fcntl.h>

 

#define MAXN 4096

#define exit_succeed 0

#define exit_failed -1

 

int cdup(const int file_flag, const int obj_flag)

{

     int i;

     int n;

     int top;

     int stack[MAXN];

 

     top = 0;

 

     if ((obj_flag>MAXN) || (obj_flag<3) || (obj_flag==file_flag))

     {

         printf("Obi_flag error!\n");

         return exit_failed;

     }

 

     while ((n = dup(file_flag)) < obj_flag)

     {

         if (-1 == n)

         {

              printf("System can not make a flag!\n");

              return exit_failed;

         }

 

         stack[top++] = n;

     }

 

     close(obj_flag);

 

     if (-1 == dup(file_flag))

     {

         printf("Function dup error\n");

         return exit_failed;

     }

 

     for (i=0; i<top; ++i)

     {

         close(stack[i]);

     }

 

     return exit_succeed;

}

 

int write_file(const int obj_flag)

{

     char buf[] = "JiaoZhuV5\n";

 

     if (write(obj_flag, buf, strlen(buf)) < 0)

     {

         printf("Write error\n");

         return exit_failed;

     }

 

     return exit_succeed;

}

 

int main(int argc, char *argv[])

{

     int obj_flag;

     int file_flag;

 

     if (3 != argc)

     {

         printf("Parameter error!\n");

         return exit_failed;

     }

 

     file_flag = open(argv[1], O_RDWR);

 

     if (-1 == file_flag)

     {

         printf("Errror! System can not open %s\n", argv[1]);

         return exit_failed;

     }

 

     obj_flag = atoi(argv[2]);

 

     if (exit_failed != cdup(file_flag, obj_flag))

     {

         if (exit_failed == write_file(obj_flag))

         {

              return exit_failed;

         }

     }

 

     return exit_succeed;

}

         上面代码仅供参考,若发现有任何不妥的地方,欢迎各位的批评指正。

posted @ 2013-03-23 09:29  Mr_Yang2012  阅读(693)  评论(0编辑  收藏  举报