zoukankan      html  css  js  c++  java
  • unix环境高级编程第三章习题的一些拙见

    写在前面:自学apue,时间有限,这个系列都是抽时间写的,目前已经看到15章,现在从头做题,如有错误还请指教。

    apue3.1:

    write和read这样的函数都属于系统调用,这里具体所指的没有缓冲区是没有用户缓冲区,而不是指没有内核缓冲区,这里以我个人的认识认为,这里write和read将数据拷贝到缓冲区后并不直接写到文件中,而是等一定条件发生后才写进去,但是具体机制还需研究。同时这里也暴露了一个问题,每次进行I/O都需要进行系统调用,这无疑是对系统资源的一种浪费,所以这也为后来的标准I/O函数库的产生做了铺垫。

    apue3.2:

    先上代码:

    #include "apue.h"
    #include <stdio.h>
    #include <fcntl.h>
    
    int dup2_self (const int ofd , const int nfd) ;
    
    int main () {
        int fd;
        int flag;
    
        fd = open ("tempfile" , O_RDWR | O_CREAT | O_TRUNC);
        flag = dup2(0 , fd);
        write (fd , "hello
    " , 6);
    }
    
    int dup2_self (const int ofd , const int nfd) {
        char *fdptr;
        int openmax = sysconf (_SC_OPEN_MAX);
        int tempfd;
        int count = 0;
        int fdarr[openmax];
        int i;
    
        if (ofd > openmax || nfd > openmax) {
            fprintf (stderr , "the arguement error
    ");
            exit (1);
        }
    
        fdptr = malloc (30 * sizeof (char));
        sprintf (fdptr , "/proc/%d/fd/%d" , getpid() , ofd);
        if (access (fdptr , 0) < 0) {
            fprintf (stderr , "the ofd is not open
    ");
            exit (2);
        }
        sprintf (fdptr , "/proc/%d/fd/%d" , getpid() , nfd);
        if (access (fdptr , 0) < 0) {
            fprintf (stderr , "the nfd is not open
    ");
            exit (3);
        }
    
        if (nfd == ofd)
            return nfd;
        close (nfd);
        
       while (tempfd = dup (ofd)) {
            if (tempfd == nfd)
                break;
            else
                fdarr[count++] = tempfd;
        }
        printf ("%d
    " , nfd);
        for ( i = 0 ; i < count ; i++)
            close (fdarr [i]);
        return nfd;
    }

    这段代码显然无法做到dup2的原子性,但是在功能上至少可以实现所需要的功能,当然可靠性我也没有非常多的验证,这个最近本的实现让我弄清楚了很多问题:第一——dup2的使用规则,其实就是将文件描述符和文件描述标志的关系去掉,重新引导到另外一个文件描述标志中上。第二——dup的使用方法,它总是返回最小的可用的文件描述符值,比如在这里nfd(这里我在linux上将这个值打印出来是3)已经close后,再dup后就直接还是3,可见close掉后还是可用的文件描述符。第三——如何查看一个进程所打开的文件描述符在/proc/pid/fd/#就可以。最后结果就是我往main中的fd write的时候,它会在标准输出显示。

    ——————————————————————————————————————————————————分割线2016.6.1

    apue3.3:

    这里我可以很容易的看见dup的作用是将函数返回的文件标志指向和自己一样的文件表项,而open的作用是使得函数返回的描述符指向另外一个文件表项,但是两者都会指向同一个V节点,那么这两者有什么不同吗?答案是,文件表项中拥有文件状态标识,当前文件的偏移,也就是说,假设现在fd1 fd2 fd3都在文件开头位置,如果我向fd1中写入一定字节后,再向fd2写入一定字节那么fd2的字节会显示在fd1后面,这时我再向fd3中写一定字节后就会覆盖前两个描述符的字节。F_SETFD这里的作用是设置文件描述符标识,而这里只有一个值,FD_CLOEXEC,属于每个文件描述符的属性。而F_SETFL则是和文件状态标识有关系,这个值在文件表项当中的。所以很容易看出fcntl fd1时F_SETFD只影响其自身。F_SETFL则影响fd1和fd2.

    apue3.4:

    这里我只给出两种情况最后的图,前者是fd的值为1时的情况,后者是fd的值为2的情况。具体原因不在赘述,能弄清dup2_self的实现,这种题目就是水到渠成。

    ——————————————————————————————————————————————————分割线2016.6.2

    apue3.5:

    这道题目是很有趣的一道题目,这个问题其实从根本上让我们认识清楚了shell命令行中的重定向到底是怎么进行的,其实就是修改标准输入输出,标准错误的文件描述符的指向,文件描述符指向shell制定的文件的文件表项。地一个例子是首先将标准输出指向outfile的文件表项,再将标准错误的指向标准输出的文件表项,其结果就是两者都指向了同一个文件表项就是outfile的文件表项。第二个例子,首先将标准错误的文件表项指向标准输出的文件表项,这一步之后两者都指向终端的标准输出,后面再将标准输出指向outfile文件的表项,其结果就是两者指向不同的文件表项。

    apue3.6:

    先上代码:

    /*************************************************************************
        > File Name: apue3_6.c
        > Author: jeff zhu
        > Mail: 908190355@qq.com 
        > Created Time: 2016年06月03日 星期五 12时53分05秒
     ************************************************************************/
    
    #include "apue.h"
    #include <fcntl.h>
    
    //#define TEST_RD 
    #define TEST_WR 
    
    int main () {
        int fd;
        char buf[1024];
        int n;
        char flag[] = "write ok
    ";
    
        if ((fd = open ("testfile" , O_RDWR | O_APPEND)) < 0) 
            err_sys ("open error");
        if (lseek (fd , 0 , SEEK_SET) < 0) 
            err_sys ("lseek error");
    
    #ifdef TEST_RD
        while ((n = read (fd , buf , 1024)) > 0)
           if (write (STDOUT_FILENO , buf , n) != n)
               err_sys ("write error");
        if (n < 0)
            err_sys ("write error");
    #endif 
    #ifdef TEST_WR
        if (write (fd , flag , strlen (flag)) != strlen (flag))
            err_sys ("write error");
    #endif
        exit (0);
    }

    这个代码,书的作者的意图很明显,希望我们主要到这样的细节——O_APPEND的作用,书上答案的解释是,read可以任意用lseek函数指定,但是write函数即使使用lseek重新定位,但是仍然会自动定位到文件的末尾将只能的内容写到文件中。在我的代码中testfile是在当前文件夹中随意建的一个文件,里面有一定的内容。当进行读测试的时候可以直接将testfile文件中的内容读到屏幕上,而进行写测试的时候,却在文件尾显示"write ok",这个答案给的结果一样。这里我认为O_APPEND这样设计的原因,其实在书上3.11节已经给出了解释,这是为了多进程的考虑,当出现竞争条件的时候,这样的设计不至于出现进程之间相互覆盖的情况。

    ——————————————————————————————————————————————————分割线2016.6.3

    写在后面:哈哈,第三章已经更新完了。

  • 相关阅读:
    orcle id和执行计划(转)
    mysql 授权
    nginx+php 安装手册
    为 MySQL 增加 HTTP/REST 客户端:MySQL UDF 函数 mysql-udf-http 1.0 发布
    Nginx提示502和504错误的解决方案
    error while loading shared libraries: xxx.so.x"错误的原因和解决办法
    lnmp memcache出问题
    Nginx下实现pathinfo及ThinkPHP的URL Rewrite模式支持
    Nginx代理与负载均衡配置与优化
    curl+ post/get 提交
  • 原文地址:https://www.cnblogs.com/zzlpp/p/5551624.html
Copyright © 2011-2022 走看看