• UNIX环境高级编程-第三章习题


    1,当读写磁盘文件时,read,write等函数确实是不带缓冲机制的吗?请说明原因。

      答:所有磁盘I/O都要经过内核的块缓存区(即内核的缓冲区高速缓存)。唯一例外的是对原始磁盘设备的I/O,但是我们不考虑这种情况。既然read或write的数据都要被内核缓冲,那么术语“不带缓冲的I/O”指的是在用户的进程中对这两个函数不会自动缓冲,每次read或write就要进行一次系统调用。

    2,编写一个与dup2功能相同的函数,要求不调用fcntl函数,并且要有正确的出错处理。

      答:

    #include <stdio.h>
    #include <errno.h>
    #include <limits.h>
    #include <unistd.h>
    #include <sys/resource.h>
    #include <fcntl.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define    OPEN_MAX_GUESS    256
    
    long
    open_max(void)  //这里是第二章的习题代码
    {
        long openmax;
        struct rlimit rl;
    
        if ((openmax = sysconf(_SC_OPEN_MAX)) < 0 || openmax == LONG_MAX) 
        {
            if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
                perror("can't get file limit");
            if (rl.rlim_max == RLIM_INFINITY)
                openmax = OPEN_MAX_GUESS;
            else
                openmax = rl.rlim_max;
        }
        return(openmax);
    }
    
    int my_dup2(int oldfd, int newfd)
    {
        int fd;
        int begin_fd;
        long t_openmax;
        int i;
        t_openmax = open_max();
        printf("open_max is %ld
    ", t_openmax);
        if(oldfd < 0 || newfd < 0 || oldfd > (t_openmax - 1) || newfd > (t_openmax - 1))  //以当前系统最大打开文件数量为限
        {
            perror("fd error");
            return -1;
        }
        
        if(oldfd == newfd)
        {
            return newfd;
        }
        close(newfd);
        fd = dup(oldfd);
        begin_fd = fd;
        while(fd < (t_openmax - 1))  //循环对比当前复制的文件描述符是否符号要求
        {
            if(fd == newfd) 
            {
                printf("get newfd
    ");
                break;
            }
            fd = dup(oldfd);
            if(fd == -1) 
            {
                perror("dup error");
                return -1;
            }
            
        }
        for(i = begin_fd;i < fd; i++)
        {
           close(i);
        }  
        return fd;
    }
    
    int main(int argc, char *argv[])
    {
        int oldfd;
        int newfd;
        
        char *buf="This is my_dup2 test
    ";
        
        if((oldfd = open("my_dup2_text.txt",O_RDWR|O_CREAT,0644)) == -1)
        {
            perror("my_dup2_text open error");
            exit(-1);
        }
        newfd = my_dup2(oldfd, 1023);
        if(newfd == -1)
        {
            perror("my_dup2 error");
            exit(-1);      
        }
        printf("newfd is %d
    ", newfd);
        if(write(newfd, buf, strlen(buf)) != strlen(buf))
        {
            perror("write error");
            exit(-1);         
        }
        
        close(newfd);
        exit(0);
    }

     3,假设一个进程执行下面3个函数调用:

    fd1 = open(path, oflags);
    fd2 = dup(fd1);
    fd3 = open(path, oflags);

      指出三个文件描述符的文件表关系。对fcntl作用于fd1来说,F_SETFD命令会影响哪一个文件描述符?F_SETEL呢?

      答:fd1、fd2指向同一个文件表,fd3有新的文件表,但是v节点表与fd1、fd2一样。F_SETFD只影响fd1,因为这个标志位的作用是设置文件描述符。F_SETEL影响fd1和fd2,因为它设置的是文件的状态。

    4,许多程序中都包含下面一段代码:

    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    if (fd > 2)
        close(fd);

      为了说明if语句的必要性,假设fd是1,画出每次调用dup2时3个描述符及相应的文件表项的变化情况。然后再画出fd为3的情况。

      答:fd为1的情况:fd标志为0、2、1都指向同样的文件表。

      fd为3的情况:fd标志为0、1、2、4都指向同样的文件表。

      因为 0、1、2分别对应stdin, stdout, stderr,是不应该关闭的,这段程序的目的是把stdin, stdout, stderr这三个标准fd重定向到同一个文件描述符里,当fd大于2时,因为目的已经达成,大于2的fd已经不需要了,为了避免造成浪费,所以关闭它。

    5,在bourne shell、Bourne-again shell和Korn shell中,digit1>&digit2表示要将描述符digit1重定向至描述符digit2的同一文件。请说明下面两条命令的区别。

    ./a.out > outfile 2>&1
    ./a.out 2>&1 > outfile

      答:第一条是把标准错误和标准输出都重定向到outfile,指向同一文件表项;

        第二条是标准错误重定向到标准输出,然后标准输出又重定向到outfile,所以标准输出指向outfile的文件表项,标准错误指向终端的文件表项,所有标准错误都会打印到终端。

    6,如果使用追加标志打开一个文件以便读、写,能否仍用lseek在任一位置开始读?能否用lseek更新文件中任一部分的数据?请编写一段程序验证。

      答:能在任一位置开始读,但不能更新任一部分的数据,只能追加,程序如下:

    #include <stdio.h>
    #include <errno.h>
    #include <limits.h>
    #include <unistd.h>
    #include <sys/resource.h>
    #include <fcntl.h>
    #include <string.h>
    #include <stdlib.h>
    int main(int argc, char *argv[])
    {
        int fd;
       
        char buf_read[10];
        char *buf="This is lseek test ";
       
        if((fd = open("lseek.txt",O_RDWR|O_CREAT|O_APPEND,0644)) == -1)
        {
            perror("fd open error");
            exit(-1);
        }
       
        if(write(fd, buf, strlen(buf)) != strlen(buf))
        {
            perror("write error");
            exit(-1);        
        }
        lseek(fd, 2, SEEK_SET);
        read(fd, buf_read, 10);
        lseek(fd, 2, SEEK_SET);
        printf("lseek read is: %s ", buf_read);
        if(write(fd, buf, strlen(buf)) != strlen(buf))
        {
            perror("write error");
            exit(-1);        
        }
        close(fd);
        exit(0);
    }

     运行结果如下:

    dog@dog:~/test$ ./a.out
    lseek read is: is is lsee
    dog@dog:~/test$ cat lseek.txt
    This is lseek test
    This is lseek test
  • 相关阅读:
    vue2.0开发聊天程序(八) 初步完成
    王下邀月熊_Chevalier的前端每周清单系列文章索引
    将HTML页面转换为PDF文件并导出
    二维码活码管理系统
    前端眼里的docker
    这些好玩的例子,希望你也能喜欢
    如何实现swipe、tap、longTap等自定义事件
    基于 HTML5 Canvas 的交互式地铁线路图
    【php学习】时间函数
    页面瀑布流布局的实现 javascript+css
  • 原文地址:https://www.cnblogs.com/mingyunrangwozoudaoxianzai/p/12360933.html
Copyright © 2020-2023  润新知