APUE第三章3.2习题分析

来源:互联网 发布:苹果录屏用什么软件 编辑:程序博客网 时间:2024/04/30 03:25

题目描述:编写一个与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对其没有限制,但是建议指定的文件描述符不要过大。如果指定的文件描述符与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 <stdio.h>
#include <unistd.h>


int main(void)
{
    int fd = -1;
    fd = mydup2(0,10);
    if(fd < 0)
    {
        perror("mydup2");
        return -1;
    }
    printf("fd = %d\n",fd);
    return 0;
}


int mydup2(int fd, int newfd)
{
    //判断fd和newfd的范围是否正确
    if(fd < 0 || fd > 256)
    {
        printf("fd is wrong.\n");
        return -1;
    }


    if(newfd <0 || newfd > 256)
      {
        printf("newfd is wrong.\n");
        return -1;
    }
      
    int index = 0;
    int fdarray[newfd];
    //判断fd是否已经被打开。
    if((fdarray[index] = dup(fd)) == -1)
    {
        printf("error while dup.\n");
        return -1;
    }
    else
    {
        close(fdarray[index]);
    }
        
    //如果相等,则直接返回。
    if(fd == newfd)
    {
        return newfd;
    }
    //将newfd关闭
    close(newfd);
   
    //获取所要的newfd
    int newfdindex;
    for(index=0; index<=newfd; index++)
    {
        fdarray[index] = dup(fd);
        if(fdarray[index] == -1)
        {
            printf("error while dup.\n");
            return -1;
        }
        else
        {
            if(fdarray[index] == newfd)
            {
                newfdindex = index;
                break;
            }
        }
    }
    //将之前打开的fd都关闭
    for(index=0; index<newfdindex; index++)
    {
        close(fdarray[index]);
    }


    return fdarray[newfdindex];
}

0 0
原创粉丝点击