深入理解计算机系统第10章笔记

on under auxilary
1 minute read

系统级I/O

1.输入/输出(I/O)是在主存和外部设备(如磁盘驱动器,终端和网络)之间拷贝数据的过程.输入操作是从I/O设备拷贝数据到主存, 而输出操作是从主存拷贝数据到I/O设备.I/O函数如printf,scanf,<<,>>

2.所有的I/O设备,如网络,磁盘和终端,都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行.这种将设备 优雅地映射为文件的方式,允许unix内核引出一个简单,低级的应用接口,称为unix I/O,这种使得所有的输入和输出都能以一种统 一且一致的方式来执行:打开文件,改变当前的文件位置,读写文件,关闭文件.

3.stat函数以一个文件名作为输入,并填写如图10-8所示的一个stat数据结构中的各个成员.其中st_size成员包含了文件的字节 数大小,st_mode成员则编码了文件访问许可位和文件类型.

4.描述符表:每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的.每个打开的描述符表项指向文件表中 的一个表项.
文件表:打开文件的集合是由一张文件表来表示的,所有的进程共享表.每个文件表的表项组成包括有当前的文件位置,引用计数 (即当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针.关闭一个描述符会减少相应的文件表表项中的引 用计数.内核不会删除这个文件表表项,直到它的引用计数为零.
v-node:同文件表一样,所有的进程共享这张v-node表.每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员.

每个描述符都有它自己的文件位置,所以对不同描述符的读操作可以从文件的不同位置获取数据.理解父子进程是如何共享文件的: 假设在调用fork之前,父进程有如图10-11所示的打开文件.然后,图10-13展示了调用fork后的情况.子进程有一个父进程描述符表 的副本.父子进程共享相同的打开文件表集合,因此共享相同的文件位置.一个很重要的结果就是,在内核删除相应文件表表项之前, 父子进程必须都关闭了它们的描述符.

5.每个ANSI C程序开始时都有三个打开的流stdin,stdout,stderr,分别对应于标准输入(对应描述符0),标准输出(对应描述符1)和 标准错误(对应描述符2)

6.ANSI C定义了一组高级输入输出函数,称为标准I/O库,为程序员提供了Unix I/O的较高级别的替代,这个库(libc)提供了打开和 关闭文件的函数(fopen和fclose),读和写字节的函数(fread和fwrite),读和写字符串的函数(fgets和fputs),以及复杂的格式化的 I/O函数(scanf和printf).应用程序可以通过open,close,lseek,read,write和stat这样的函数来访问Unix I/O.较高级别的RIO和 标准I/O函数都是基于(使用)Unix I/O函数来实现的.RIO函数是专为本书开发的read和write的健壮的包装函数,它们自动处理不足 值,并且为读文本行提供一种高效的带缓冲的方法.

7.大多数C程序员在他们的职业生涯中只使用标准I/O,而从不涉及低级Unix I/O函数,不幸的是,当我们对网络输入输出使用标准 I/O时,它却带来了一些令人讨厌的问题,我们建议你在网络套接字上不要使用标准I/O函数来进行输入和输出,而要使用健壮的 RIO函数.

8.标准I/O库是基于Unix I/O实现的,并提供了一组强大的高级I/O例程,对于大多数应用程序而言,标准I/O更简单,是优于Unix I/O 的选择,然而,因为对标准I/O和网络文件的一些相互不兼容的限制,Unix I/O比标准I/O更适用于网络应用程序.图10-15为Unix I/O,标准I/O和RIO之间的关系.

csapp
home
github
archive
category