• 信息安全系统设计基础第九周学习总结—20135227黄晓妍


    第十章系统级I/O

    输入/输出(I/O)是主存和外部设备(I/O设备)(如磁盘驱动器、终端、网络)之间拷贝数据的过程。输入是从I/O设备拷贝到主存。反之则反。

    学习Unix I/O的原因:

    帮助理解其他的系统概念。

    有时只能使用Unix I/O。例如:读取文件元数据(文件大小和创建时间)。另外,使用标准I/O库进行网编程非常冒险。

             10.1Unix I/O

    Unix文件就是一个m字节的序列:b0,b1,b2….bm-1。所有的I/O设备都被虚拟化为文件。所有的输入输出都是在当成相对应的文件的读写。将设备映射为文件,Unix内核引出一个应用接口,Unix I/O。

    输入输出的执行方式:

    打开文件:

    打开文件,内核会返回描述符。标准输入(STDIN_FILENO)描述符为0、标准输出(STDOUT_FILENO)描述符为1、标准错误(STDERR_FILENO)描述符为2。

    改变当前文件位置:

             文件位置k,是文件开头起始的字节偏移量。

    读写文件:

    读是从文件拷贝到存储器。写相反。当k超过文件字节数m时,会触发end-of-file(EOF)条件。

    关闭文件:

    释放文件打开时创建的数据结构(释放文件的存储器资源),将描述符恢复到可用的描述符池中。

             10.2打开和关闭文件

                       open函数的返回值是描述符。

                       filename文件路径字符串。

                       flag参数指明进程打算怎么访问这个文件。flag参数的值:

            

            

                       mode参数指定了新文件的访问权限位。mode参数的值:

          

             10.3读和写文件

                       read 执行输入(读)

                       write执行输出(写)

                       read 函数:从fd的当前文件位置 拷贝 最多n个字节到存储器位置 buf。

                                         返回值-1表示错误,0表示EOF,否则表示实际传送的字节数。

                       write 同理。

                       不足值:read和write传送的字节数少于应用程序的要求。

                                         读时遇到了EOF

                                         从终端读文本行:如果打开的文件是与终端相联的,那么每个read函数                                                                              将一次传送一个文本行,不足值=文本行大小。

                                         读和写网络套接字

             10.4RIO包健壮地读写

                       RIO包能自动地处理不足值。提供了:无缓冲的输入输出函数,带缓冲的输入函数。

                       10.4.1RIO的无缓冲的输入输出函数

    rio_readn函数从fd拷贝最多n字节到usrbuf。rio_writen也一样。rio_readn遇到EOF时只返回一个不足值,rio_writen绝不会返回不足值。对同一描述符,无缓冲的两个函数可以交叉调用

    当errno==EINTR时,表示函数被一个应用信号处理程序的返回中断了,则本次读的字节为0,重新使用read函数接着读入。

                       10.4.2RIO的带缓冲的输入函数        

    文本行就是一个由换行符结尾的ASCII码字符序列。换行符数字值为0x0a.rio_readlineb函数从内部读缓冲区拷贝一个文本行,当缓冲区为空时,会自动地调用read重新填满缓冲区。rio_readn带缓冲区的版本:rio_readnb。

                                rio_readinitb函数将fd和rp处的一个类型为rio_t的读缓冲区联系起来。

    rio_readlineb从rp读出一个文本行(包括换行符)并把它存到usrbuf,并用空字符结束这个文本行。最多读maxlen-1个字节,剩下一个给结尾处的空字符。

                                rio_readnb最多读n个字节。

                                对同一描述符,带缓冲的函数之间可以交叉调用。

                     

                                示例为RIO函数一次一行地从标准输入拷贝一个文本文件到标准输出。

                                

                                rio_t读的缓冲区结构体。以及初始化它的代码。

                                

    rp->rio_cnt为缓冲区未读的字节。出错返回-1,EOF返回0,正常就接着读,直到>0。为0表示缓冲区为空,一旦为空就调用read将其填满。在缓冲区非空时,将n和rp->rio_cnt中的最小值拷贝到usrbuf,并且返回这个最小值。

                                

    rio_readlineb函数与rio_read相似,不同之处在于,每次调用都从读缓冲区返回一个字节,然后检查这个字节是否是换行符。

                                

                                与rio_readn相似。

             10.5读取文件元数据

             

             检索文件元数据的方式:调用stat和fstat函数。两者功能相似。

             

             stat数据结构中的成员。重点掌握st_mode,st_size.

             st_size:文件字节数大小

             st_mode:文件访问许可位和文件类型。(普通文件:二进制文件和文本文件。目录文件:其他文件信息。套接字:通过网络与其他进程通信的文件。)

             

        

             判断了是三种文件的哪一种。(注意套接字是用“other”表示的)只判断了文件拥有者是否可读。

             10.6共享文件

             用三个相关的数据结构表示打开的文件:

                       描述符表:每个打开的描述符表项指向文件表中的一个表项。

                       文件表:打开的文件的集合是由一张文件表表示的,所有的进程共享这张表。包括文件位置、引用计数(当前指向该表项的描述符表项数),指向v-node表的指针。

                       v-node表:包含stat结构中大多数信息。

             

             打开文件的内核数据结构

             

             文件共享。共享了同一个磁盘文件

            

             子父进程共享文件。子进程有一个父进程描述表符副本,所以他们共享打开文件的集合。注意,在内核删除相应文件表表项之前,子父进程必须都关闭他们的描述符。

             10.7 I/O重定向

             

    拷贝oldfd到newfd,将newfd的内容覆盖掉。如果newfd已经打开了,dup2会在覆盖前将它关闭。

             

    使用dup2函数将描述符1重定向到描述符4。

             10.8 标准I/O

             标准I/O库:一组高级输入输出函数。将一个打开的文件模型化为一个流,一个流即一个指向FILE类型的结构的指针。每个ANSI C程序开始时都有三个打开的流:stdin(标准输入),stdout(标准输出),stderr(标准错误)。

             类型为FILE的流是对文件描述符和流缓冲区的抽象。为了减小系统开销。

             10.9 综合:该使用哪些I/O函数

             大多数时候使用标准I/O就可以了。

             在网络套接字的时候使用RIO函数。需要格式化输出,使用sprintf函数格式化一个字符串,然后用rio_writen把它发送到套接口。格式化输入,使用rio_readlineb读一个完整的文本行,再使用scanf从文本行提取不同字段。

    小结:

      本章内容相对较少,但是花费的时间一点都没有减少,在阅读代码上花费了较多时间。明显可以从阅读中看出本章与其他章的关联较大,有许多伏笔。本章主要是帮助我们理解系统级的输入输出,Unix I/O,告诉我们虽然我们有一些高级的标准库函数可以使用,但是在一些情况下,比如查看元数据,比如网络套接字时,必须使用系统级I/O。重点在于如何使用RIO包解决不停返回不足值这个问题。

     疑问:

      在书上p603上rio_read函数中,erro!=EINTR旁边的注释写的是被应用信号处理程序的返回中断,但是p601的rio_readn函数中,erro==EINTR才是被中断,我想了一下,满足这个条件return -1,说明这里是出错,应该是书上p603的注释有误。

    参考资料: 《深入理解计算机系统》

  • 相关阅读:
    java中原子操作的实现分析
    AQS源码分析
    Java JNDI 学习
    门面模式、代理模式、适配器模式的区别
    tomcat源码阅读之StandardWrapper解析
    tomcat源码阅读之过滤器
    tomcat源码阅读之SingleThreadModel
    tomcat源码阅读之单点登录
    技术人员的八条宝贵经验,时刻提醒自己,共勉之
    tomcat源码阅读之安全机制
  • 原文地址:https://www.cnblogs.com/angelahxy/p/4947681.html
Copyright © 2020-2023  润新知