20145308 《信息安全系统设计基础》第9周学习总结
教材学习内容总结
- 输入/输出(I/O)是在主存和外部设备之间拷贝数据的过程
10.1 Unix I/O
- Unix文件:m个字节的序列
- 所有的I/O设备都被模型化为文件,所有的输入和输出都被当作对相应文件的读和写来执行
- Unix内核引出一个简单、低级的应用接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行
- 打开文件:宣告想要访问一个I/O设备,内核返回描述符(小的非负整数)
- 改变当前的文件位置:内核保持着一个文件位置k,是从文件开头起始的字节偏移量
- 读写文件:文件从当前文件位置K开始读写
- 关闭文件:内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中
10.2 打开和关闭文件
- 进程是通过调用open函数来打开一个已存在的文件或创建一个新文件的
- open成功返回新文件描述符,出错为1
- open函数:filename文件描述符,flags指明进程打算如何访问文件,mode指定了新文件的访问权限位
- 文件的访问权限位被设置为mode&umask
- close成功为0,出错返回-1
10.3 读和写文件
- 应用程序分别通过调用read和write函数来执行输入和输出的
- read成功返回读的字节数,若EOF为0,出错为-1
- write成功则为写的字节数,出错则为-1
- 不足值出现原因
- 读时遇到EOF
- 从终端读入文本行:打开文件是与终端相关联的,每个read函数将一次传送一个文本行,返回的不足值等于文本行的大小
- 读和写网络套接字:打开的文件对于网络套接字,内部缓冲约束和较长的网络延迟会引起read和write返回不足值
10.4 用RIO包健壮地读写
- RIO:I/O包,会自动为你处理不足值
- RIO提供两种函数
- 无缓冲的输入输出函数:直接在存储器和文件之间传送数据,没有应用级缓冲,对二进制数据读写到网络和从网络读写二进制数据
- 带缓冲的输入函数:允许高效的从文件中读取文本行和二进制数据,这些文件的内容缓存在应用级缓冲区内,带缓冲的RIO输入函数是线程安全的,在同一个描述符上可以被交错的调用
10.4.1 RIO的无缓冲的输入输出函数
- 通过调用rio_readn和rio_writen函数,应用程序可以在存储器和文件之间直接传送数据
- 成功则为传送的字节数,EOF则0(只对rio_readn),出错则为-1
- rio_writen遇到EOF绝不会返回不足值
- 对同一个描述符,可以交错调用rio_readen和rio_writen
10.4.2 RIO的带缓冲的输入函数
- 文本行:一个由换行符结尾的ASCII码字符序列
- 换行符(' ')与ASCII码中(LF)相同,数字值为0x0a
- 包装函数rio_readlined,从一个内部读缓冲区拷贝一个文本行,当缓冲区变空时,自动调用read重新填充缓冲区
- rio_readnb,对于即包含文本行也包含二进制数据的文件,rio_readn带缓冲区的版本
- RIO读程序的核心是rio_read函数,Unix read函数的带缓冲版本
10.5 读取文件元数据
- 应用程序能够通过调用stat和fstat函数,检索到关于文件的信息(文件的元数据),成功为0,出错为-1
- st_size包含了文件的字节数大小,st_mode成员编码了文件访问许可位和文件类型
- 普通文件:包括某种类型二进制或文本数据
- 目标文件:包含关于其他文件信息
- 套接字:一种用来通过网络与其他进程通信的文件
- 使用宏和stat函数来读取和解释一个文件的st_mode位
10.6 共享文件
- 内核用三个相关的数据结构表示打开的文件:描述符表、文件表、v-node表
- 描述符表:每个进程都有独立的描述符表,表项是由进程打开的文件文件描述符来索引的,每个描述符表项都指向文件表中的一个表项
- 文件表:打开的文件的集合,所有进程共享一个表,表项组成包括当前的文件位置、引用计数和指向v-node表对应表项的指针
- v-node表:所有进程共享,表项包括stat结构中的大多数信息
10.7 I/O重定向
- Unix外壳提供I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来
- 利用int dup2(int oldfd,int newfd),成功返回非负描述符,出错为-1
- dup2函数拷贝描述表表项oldfd到描述表表项newfd,覆盖newfd以前的内容,如果newfd已经打开了,dup2会在拷贝oldfd前关闭newfd
10.8 标准I/O
- 标准I/O库,一组高级的输入输出函数,将一个打开的文件模型化为一个流(指向FILE类型的结构的指针)
- ANSI C程序开始时有三个打开的流:标准输入stdin、标准输出stdout和标准错误stderr
- 类型为FILE的流是对文件描述符和流缓冲区的抽象
10.9 综合:我该使用哪些I/O函数
- 标准I/O函数是磁盘和终端设备I/O之选
- 标准I/O流限制
- 跟在输出函数之后的输入函数:在每个输入操作前刷新缓冲区
- 跟在输入函数之后的输出函数:对同一个代开的套接字打开两个流,一个用来读,一个用来写
- 在网络套接字上不使用标准I/O函数来进行输入和输出,使用健壮的RIO函数
附录A 错误处理
- 给定某个系统程序的包装函数,包装函数调用基本函数并检查错误
A.1 Unix系统中的错误处理
- Unix风格的错误处理
- Unix早期开发出来的函数返回值既包括错误代码又有有用结果,例如fork和wait
- 遇到错误返回-1,并将全局变量errno设置为指明错误原因的错误代码
- Posix风格的错误处理
- 只用返回值来表明成功(0)或失败(非0),任何有用的结果都返回在通过引用传递进来的函数参数中
- DNS风格的错误处理
- gethostbyname和gethostbyaddr函数检索DNS主机条目,在失败时返回NULL指针,并设置全局变量h_errno
- 错误报告函数小结
A.2错误处理包装函数
- Unix风格的错误处理包装函数
- Posix风格的错误处理包装函数
- DNS风格的错误处理包装函数
教材学习中的问题和解决过程
- 习题5.1,答案不是'
- 看了题目后,以为是分别两次读文件,就直接认为答案是'f'了,但是看了讲解,发现自己忽略了重定向后,两个文件描述符都指向一个文件,文件的引用计数也要加一,答案是'o'
本周代码托管截图
托管链接:http://git.oschina.net/yg1022/CSAPP2E
其他(感悟、思考等,可选)
- 本周学习了I/O,其中包含Unix系统提供的少量的系统级函数,利用RIO包读写,和利用基于Unix I/O的标准I/O库进行读写。还学习了附录A中的内容,主要学习了Unix系统中的错误处理以及用包装函数来处理错误。学习了两部分内容,相同点是无论是I/O还是错误,都会用包装函数来处理错误。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 1/2 | 25/30 | 学习Linux指令 | |
第二周 | 50/50 | 1/3 | 25/55 | Linux系统下的开发环境 |
第三周 | 20/70 | 1/4 | 25/80 | 信息的表示和处理 |
第五周 | 20/90 | 1/5 | 30/110 | 程序的机器级表示 |
第六周 | 20/110 | 1/6 | 30/140 | 处理器体系结构 |
第七周 | 20/130 | 1/7 | 30/170 | 存储器层次结构 |
第八周 | 0/130 | 2/9 | 10/180 | 期中复习 |
第九周 | 48/178 | 1/10 | 10/190 | 系统级I/O、错误处理 |