• 信息安全系统设计基础第九周学习总结


    第十章  系统级I/O

    内容总结:

    一、每个unix文件都是一个m字节的序列;所有I/O设备,如网络、磁盘和终端都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行。

    二、输入/输出(I/O)是在主存和外部设备之间拷贝数据的过程。输入操作是从I/O设备拷贝数据到主存,输出操作是从主存拷贝数据到I/O设备。

    三、 I/O重定向:

         1、Unix外壳提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。

           unix > ls > foo.txt

           使外壳加载和执行ls程序,将标准输出重定向到磁盘文件foo.txt。

         2、I/O重定向函数: dup2

             函数定义为:

        #include <unistd.h>

        int dup2(int oldfd, int newfd);

        返回:若成功则为非负的描述符,若出错则为-1。

        dup2函数拷贝描述符表表项oldfd到描述符表表项newfd,覆盖描述符表表项newfd以前的内容,如果newfd被打开了,dup2会在拷贝oldfd之前关闭newfd。

    四、标准I/O

          1、ANSI C定义了一组高级输入输出函数,称为标准I/O库,包含:

           (1)fopen、fclose,打开和关闭文件

           (2)fread、fwrite,读和写字节

           (3)fgets、fputs,读和写字符串

           (4)scanf、printf,复杂的格式化的I/O函数

           2、标准I/O库将一个打开的文件模型化为一个流。对于程序员而言,一个流就是一个指向FILE类型的结构的指针。

           3、每个ANSI C程序开始的时候都有三个打开的流:stdin、stdout、stderr,分别对应于标准输入、标准输出和标准错误:

         #include <stdio.h>

         extern FILE *stdin;

         extern FILE *stdout;

         extern FILE *stderr;

           类型为FILE的流是对文件描述符和流缓冲区的抽象。流缓冲区的目的和RIO读缓冲区的一样:就是使开销较高的Unix I/O系统调用的数量尽可能的小。

    五、Unix I/O是在操作系统内核中实现的。应用程序可以通过open、close、lseek、read、write和stat这样的函数来访问Unix I/O。

    六、标准I/O流,从某种意义上而言是全双工的,因为程序能够在同一个流上执行输入和输出。然而 ,对流的限制和对套接字的限制,有时候会互相冲突,而又极少有文档描述这些现象:

      限制一:跟在输出函数之后的输入函数。

      限制二:跟在输入函数之后的输出函数。

    七、在网络套接字上不要使用标准I/O函数来进行输入和输出,而是使用健壮的RIO函数。

    课后练习题:

    练习题1

    下面的程序输出是什么?

    #include "csapp.h"

    int main()

    {

          int fd1, fd2;

          fd1 = Open("foo.txt", O_RDONLY, O);

          Close(fd1);

          fd2 = Open("baz.txt", O_RDONLY, O);

          printf("fd2 = %d ", fd2);

          exit(0);

     }

    答案:Unix进程生命周期开始时,打开的描述符赋给了stdin(描述符0)、stderr(描述度2)。open函数总是返回最低的未打开的描述符,所以第一次调用open会返回描述符3.调用close函数会释放描述符3,最后对open的调用会返回描述符3,因此程序的输出是”fd2=3“.

    练习题2

    假设磁盘文件foobar.txt由6个ASCII码字符“foobar”组成。那么下列程序的输出是什么? 程序如下:

    #include "csapp.h"

    int main()

    {

          int fd1, fd2;

          char  c;

          fd1 = Open("foobar.txt", O_RDONLY, O);

          fd2 = Open("foobar.txt", O_RDONLY, O);

          Read(fd, &c, 1);

          Read(fd2, &c, 1);

          printf("c = %c ", c);

          exit(0);

    }

    答案: 描述符fd1和fd2都有各自的打开文件表表项,所以每个描述符对于foobar.txt都有它自己的文件位置。因此,从fd2的读操作会读取,foobar.txt的第一个字母,并输出 c = f

    练习题3

    就像前面一样,假设磁盘文件foobar.txt由6个ASCII码字符”foobar“组成。那么下列程序的输出是什么?

    #include "csapp.h"

    int main()

    {

          int fd;

          char c;

          fd = Open("foobar.txt", O_RDONLY, O);

          if(Fork()==0){

             Read(fd, &c, 1);

             exit(0);

          }

          Wait(NULL);

          Read(fd, &c, 1);

          printf("c = %c ", c);

          exit(0);

    }

    答案:因为子进程会继承父进程的描述符表,以及所有进程共享的同一个打开文件表。因此,描述符fd在父子进程中都指向同一个文件表表项。当子进程读取文件的第一个字母时,文件位置加1.因此,父进程会读取第二个字节,而输出就是c = 0

    练习题4

    如何用dup2将标准输入重定向到描述符5?

    答案: 重定向标准输入(描述符0)到描述符5,我们将调用dup2(5,0)或者等价的dup2(5,STDIN_FILENO).

    练习题5

    假设磁盘文件foobar.txt由6个ASCII码字符“foobar”组成。那么下列程序的输出是什么?

    #include "csapp.h"

    int main()

    {

          int fd1, fd2;

          char  c;

          fd1 = Open("foobar.txt", O_RDONLY, O);

          fd2 = Open("foobar.txt", O_RDONLY, O);

          Read(fd2, &c, 1);

          Dup2(fd2, fd1);

          Read(fd1, &c, 1);

          printf("c = %c ", c);

          exit(0);

    }

    答案:因为我们将fd1重定向到了fd2,输出实际上是c = 0.

    参考资料

     《深入理解计算机系统》

    心得体会:

      本周将书本第十章的内容重新看了一遍,重点放在了I/O这一块,然后认真做了课后的练习题,发现对内容的掌握更深一步。

  • 相关阅读:
    Go 函数
    Go 基础
    Emmet使用详解
    Linux系统安装7.4
    NTP时间服务
    部署Java和Tomcat
    Linux用户管理
    Linux定时任务
    Linux正则详解
    Linux目录结构
  • 原文地址:https://www.cnblogs.com/20135235my/p/4972643.html
Copyright © 2020-2023  润新知