UNIX环境高级编程习题之第三章第二题

不调用fcntl函数实现dup2函数


问题描述

dup2函数头定义为int dup2(int fd, int fd2),返回值为fd2指定的文件描述符,指向fd指向的文件,如果fd2已经打开,则需先关闭;如果fd == fd2,则无需关闭fd2。

解题思路

1、寻找需要的文件描述符
不能调用fcntl,那么我们只能调用dup函数,这个函数会返回当前可用的文件描述符中的最小值,循环n次调用直到返回值等于fd2。

2、调用dup的负面影响
这个时候我们打开了n-1个无用的文件,这些并不是我们需要或者预期的,返回前需关闭。否则不但会占用大量系统资源,使得系统无法打开新的文件,甚至这些预期之外的文件描述符也可以访问或者修改文件,形成安全隐患。

3、消除dup造成的隐患
线性结构记录n-1个文件描述符,并依次关闭

4、错误error处理
dup调用错误:包括指定的fd2过大,打开的文件描述符超出限制。在不考虑其他程序也调用此函数的情况下,我们可以通过sysconf函数来获取打开上限。

5、测试问题
定义一个文件描述符x指向标准输出,并通过x写入一段特定的字符,查看是否会在标准输出是打印,也可以直接重定向到指定文件查看。

代码实现

本文采用c语言实现该逻辑:

#include "apue.h"
#include <myerr.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>

#ifdef OPEN_MAX
static long openmax = OPEN_MAX;
#else
static long openmax = 0;
#endif

int mydup(int fd, int fd2){
    //获取系统允许的最大的文件数
    errno = 0;
    if (openmax == 0)
        openmax = sysconf(_SC_OPEN_MAX);
    if (openmax < 0){
        if (errno != 0){ //这个值是不确定的
            printf("OPEN_MAX这个值是不确定的,设为默认100\n");
            openmax = 100;
        }
        else{ //获取OPEN_MAX错误
            printf("获取OPEN_MAX错误,设为默认100\n");
            openmax = 100;
        }
    }else
        printf("OPEN_MAX获取成功,其值是%ld\n", openmax);

    //关闭指定的fd2文件
    errno = close(fd2);
    //关闭文件不一定会成功,因为有可能这个文件本身就没有打开,所以错误也不退出
    if (errno == -1) 
        printf("关闭fd2错误:%d",errno);

    //获取待返回的文件描述符fd1
    long fd1 = -1;
    int arr[openmax-1], idx = 0,i;
    for (i = 0; i < openmax - 1; i++){// 初始化线性结构
        arr[i] = -1;
    }
    do{//循环调用dup函数直至返回的fd1 == fd2
        fd1 = dup(fd);
        if (fd1 > 0){//调用成功
            if (fd1 == fd2){//如果调用成功,退出循环
                break;
            }else{
                arr[idx] = fd1;
                idx++;
            }
        }
    }while(fd1 < fd2);

    //关闭打开的多余的文件
    for (i = 0; i < openmax - 1; i++){
        if (arr[i] == -1)
            break;
        else{
            errno = close(arr[i]);
            if (errno == -1){
                printf("关闭文件%ld错误",arr[i],stdout);
                if (idx != i){
                    idx = i;
                    i--; //关闭失败回退再关闭一次
                }
            }
        }
    }

    return fd1;
}

int main(void){
    int fdtest = dup(1);
    char buf[] = "hello, mydup for dup2!\n";
    printf("打开的文件是:%d,buf长度是%d\n",fdtest,strlen(buf));
    int fd = mydup(STDOUT_FIFLNO,fdtest);
    printf("mydup返回的文件是:%d\n",fd);

    //测试返回的文件符是否可以直接操作标准输出
    if (write(fd, buf, strlen(buf)) != strlen(buf))
        err_sys("buf write error\n");

    exit(0);
}

在Linux环境下的运行结果如下:

打开的文件是:3,buf长度是23
OPEN_MAX获取成功,其值是102400
mydup返回的文件是:3
hello, mydup for dup2!

可见测试的buf成功通过获取的文件描述符写入到了标准输出中,至此测试完毕。


猜你喜欢

转载自blog.csdn.net/l350230259/article/details/70822764