信息安全系统设计基础 第9周学习笔记

系统级I/O

10.1 Unix I/O

  • 一个unix文件就是一个m字节的序列(b0b1b2...bm-1)。

    所有的IO设备,如网络,磁盘,终端,都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。

10.2 打开和关闭文件

  • open函数将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。

    • 打开标志flags有三种基本标志:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(可读可写)。

    • 也可以和其他三种(O_CREAT、O_TRUNC、O_APPEND)组合使用。

       O_CREAT:如果文件不存在,就创建它的一个截断的(空的)文件。
      
       O_TRUNC:如果文件已经存在,就截断它。
      
       O_APPEND:在每次写操作前,设置文件位置到文件的结尾处。
      

10.3 相关函数

  • open、close、read、write。具体定义可以参见man手册。

    • 某些情况下,原始的read,write传送的字节比应用程序要求的要少,这些不足值(short count)不一定是错误(意为,比如read函数参数要读5个字节,结果只读了3个字节,即小于5),下面的情况下将可能发生不足值:

        读时遇到EOF。
      
        从终端读文本行。
      
        读和写网络套接字。
      

10.4 用RIO包健壮地读写

  • 这个包会处理上面的不足,RIO提供了方便、健壮和高效的I/O。提供了两类不同的函数:

    • 无缓冲的输入输出函数 直接在存储器和文件之间传送数据,没有应用级缓冲,它们对将二进制数据读写到网络和从网络读写二进制数据尤其有用。

    • 带缓冲的输入函数

        ssize_t rio_readn(int fd,void *usrbuf,size_t n);
      
        ssize_t rio_writen(int fd,void *usrbuf,size_t n);
      
  • 对同一个描述符,可以任意交错地调用rio_readn和rio_writen。一个问本行的末尾都有一个换行
    符,那么像读取一个文本中的行数怎么办,使用read读取换行符这个方法不是很妥当,可以调用一个包装函数(rio_readineb),它从一个内部读缓冲区拷贝一个文本行,当缓冲区为空时,会自动地调用read重新填满缓冲区。也就是说,这些函数都是缓冲区操作而言的。

  • 函数是线程安全的:它在同一个描述符上可以被交替地调用。

10.5 读取文件元数据

  • 元数据:关于文件的信息,如创建时间,修改时间,metadata。可以调用stat,fstat函数。

  • 文件类型:

      普通文件:二进制或文本数据,宏指令:S_ISREG()
    
      目录文件:包含其他文件的信息,宏指令:S_ISDIR()
    
      套接字:通过网络和其他进程通信的文件,宏指令:S_ISSOCK()
    

10.6 共享文件

  • 内核用三种相关的数据结构来表示打开的文件。

    • 描述符表:它的表项由进程打开的文件描述符来索引的。

    • 文件表:打开文件的集合是一张文件表来表示的,所有的进程共享这张表。

    • v-node表:同文件表一样,所有的进程共享这张v-node表。每个表项包含stat结构中的大部分信息,如文件大小等。

  • 多个描述符也可以通过不同的文件表项来引用同一个文件。

10.7 I/O重定向

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

      unix > ls > foo.txt
    
      实际是dup2函数(one case)。dup2函数对文件描述符表项进行重定位。
    

10.8 标准I/O

  • 标准函数如fopen,fclose,fread,fwrite,fgets,fputs,scanf,printf。

  • 标准IO库将一个打开的文件模型化为一个流,对于程序员来说,一个流就是一个指向类型为FILE结构的一个指针。每个ANSI C程序开始都有三个打开的流stdin,stdout,stderr,分别对应于标准输入、输出、错误。

  • 类型为FILE的流是对文件描述符和流缓冲区的抽象。

  • 标准I/O流,从某种意义上而言是全双工的,因为程序能够在同一个流上执行输入和输出。但是有一些限定:

    • 限定1:输入函数跟有输出函数之后。如果中间没有fflush,fseek,fsetpos或rewind的调用,一个输入函数不能跟随在一个输出函数之后。fflush清空与流相关的缓冲区,后三个函数使用unix IO lseek函数来重置当前文件的位置。

    • 限定2:输出函数跟有输入函数之后。情况类同上。
      这些限定给网络应用带来一个问题:因为对套接字使用lseek是非法的。用Rio包可以解决这个问题。用sprintf把输出格式化一个字符串,通过rio_writen输出,傅rio_readlineb来读一行,用scanf来从文本中提取不同的字段。

参考资料:

  • 深入理解计算机系统(第二版)pdf

  • 深入理解计算机系统笔记,系统级I/O

读书小结

  • Unix内核使用三个相关的数据结构来表示打开的文件。描述符表中的表项指向打开文件表中的表项,而打开文件表中的表项又指向v-node表中的表项。每个进程都有它自己单独的描述符表,而所有的进程共享同一打开文件表和v-node表。

  • 有一些代码还存在不明白的地方。

posted @ 2015-11-08 20:18  20135312吴汉彦  阅读(182)  评论(1编辑  收藏  举报