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

第十章 系统级I/O

10.1 unix i/o 596

一个Unix文件就是一个m个字节的序列,所有的I/O设备都被模型化为文件,而所有的输入和输出都被当做对应文件的读和写来执行。这被称为UnixI/O,使得所有的输入和输出能以一种统一且一致的方式来执行:

1、打开文件

应用程序向内核发出请求→要求内核打开相应的文件→内核返回文件描述符

Unix外壳创建的每个进程开始时都有三个打开的文件:

标准输入——0(STDIN_FILENO)

标准输出——1(STDOUT_FILENO)

标准错误——2(STDERR_FILENO)

2、改变当前的文件位置

对于每个打开的文件,内核保持着一个文件位置k,初始为0。这个文件位置是从文件开头起始的字节偏移量。通过执行seek操作设置文件位置为k。

3、读写文件

(1)读操作

读操作就是从文件拷贝n>0个字节到存储器,并且改变文件当前位置。(如果当前位置是k,则改变为k+n) EOF的来源: 文件结尾处没有明确的EOF信号,是当文件当前位置的数值超过了文件大小时,会处罚一个称为end-of-file的条件,能够被应用程序检测到,这就是所谓的EOF信号。

(2)写 写操作是从存储器拷贝n>0个字节到一个文件,然后更新当前文件位置。

10.2 打开和关闭文件

  • open函数将filename转换为一个文件描述符,并且返回描述符数字。

打开一个已存在的文件或者创建一个新文件:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>


 int open(char *filename,int flags,mode_t mode) (若成功则返回新文件描述符,若出错为-1)

  

  • flags参数指明了进程如何访问文件,常见取值:

    ORDONLY:只读 OWRONLY:只写 ORDWR:可读可写 一个或者更多位掩码的或 OCREAT:文件不存在,就创建新文件 OTRUNC:如果文件存在,就截断它 OAPPEND:写操作前设置文件位置到结尾处

  • mode:指定了新文件的访问权限位,符号名字如下所示:

  • 关闭一个打开的文件:

    #include <unisted.h>
    
    int close(int fd)(若成功则为0,若出错则为-1)
    

      

返回值:成功返回0,出错返回-1 关闭一个已经关闭的描述符会出错

fd:即文件的描述符。

10.3 读和写文件

  • 读文件:read函数从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf。返回值表示实际传送的字节数量,错误返回-1,EOF返回0。

    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t n);
    
  • 写文件:write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。

    #include <unistd.h>
    ssize_t write(int fd, void *buf, size_t n);
    
  • 通过调用lseek函数,应用程序可以显示地修改当前文件的位置。

  • 出现不足值(指在某些情况下,read和write传送的字节比应用程序要求的要少)的原因:

    1.读的时候遇到EOF:文件末尾剩余的字节数不足读取文件的字节片大小。

    2.从终端读文本行:若打开文件与终端相关联,则每个read函数将一次传送一个问本行。返回的不足值等于文本行的大小。

    3.读和写socket:若打开的文件对应于网络套接字,那么内部缓冲约束和较长的网络延迟会引起read和write返回不足值。

10.4 用RIO包健壮地读写

1、RIO的无缓冲的输入输出函数

rioreadn函数和riowriten函数,应用程序可以在存储器和文件之间直接传送数据:

#include "csapp.h"

ssize_t rio_readn(int fd, void *usrbuf, size_t n);
ssize_t rio_writen(int fd, void *usrbuf, size_t n);

  

若成功则返回传送成功的字节数,若EOF则为0(只对rio_readn而言),若出错 则为-1。

2.RIO的带缓冲的输入函数

rio_ readlineb和rio_readnb函数从一个内部读缓冲区拷贝一个文本行,当缓冲区变空时,会自动调用read重新填满缓冲区。

void rio_readinitb(rio_t *rp,int fd);(无返回)

ssize_t rio_readlineb(rio_t *rp,void *usrbuf,size_t maxlen);

ssize_t rio_readnb(rio_t *rp,void *usrbuf,size_n);

  

若成功则返回传送成功的字节数,若EOF则为0,若出错 则为-1。

打开每一个描述符都会调用一次rioreadinitb函数,他将描述符fd和地址rp处的一个类型为riot的读缓冲区联系起来。

10.5 读取文件元数据

应用程序能通过调用stat和fstat函数,检索到关于文件的信息(元数据)。

#include <unistd.h>
#include <sys/stat.h>

int stat(const char *filename, struct stat *buf);
int fstat(int fd,struct stat *buf);

返回值:成功为0,错误为-1

st_size:包含文件的字节数大小

st_mode:包编码文件访问许可位和文件类型。

  • 普通文件包括某种类型的二进制或文本数据。

  • 目录文件包含关于其他文件的信息。

  • 套接字是一种用来通过网络与其他进程通信的文件。

10.6 共享文件

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

  • 描述符表:表项由进程打开的文件描述符来索引的,每个打开的描述符表指向文件表中的一个表项,每个进程有其独立的描述符表。

  • 文件表:打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。包括:当前的文件位置、引用计数、以及一个指向v-node表中对应表项的指针。

  • v-node表:每个表项包含stat结构中的大多数信息,;包括stmode和stsize成员,所有进程共享。

 

参考资料

1.《深入理解计算机系统》教材

2.小组问题:第十章关于csapp.h的提问 http://group.cnblogs.com/topic/73278.html

实践项目

首先把老师的压缩包在虚拟机中解压缩,运行每个代码

1、cp的作用就是读取一个文件的内容到存储器,在新的地址创建空白文件,再从存储器将内容写入新文件。(如下图把ls1.c复制,存为lc.c文件)

2、ls1程序的作用是在当前目录显示文件名(未带参数直接显示,带参数的存入argc)

3、ls2不仅显示了文件名,还用来显示文件的详细信息,比如用户名、群组名、大小、创建时间、读写权限等。

4、echostate代码用来检查命令行中的提示符是否显示的,如果显示,输入的命令都可见,不显示则表示输入的命令不可见。

5、fileinfo代码这个功能用来实现显示文件信息,建立了一个stat数据结构。先判断命令是否有操作数,有的话才能继续进行下去,如果没有报错就打印出来相关文件信息,报错就用perror将报错信息打印出来。

6、filesize代码用st_size成员来计算文件的字节数大小,gcc后有一个警告,调用正常。

7、setecho代码用来改变echo状态。

8、spwd代码的功能是列出当前目录。

9、testioctl代码用来显示当前文件的大小

习题筛选:

10.1

1、首先,建立相关文件10-1.c、foo.txt、baz.txt

2、将娄老师开学时上传的CSAPP.2nd.code文件解压至虚拟机中,从中找到libcsapp32.a静态库文件、csapp.h、csapp.c,把它们放在10-1.c所在的Terminal的主文件夹中。因为虚拟机为32位,.c文件中才是定义的那些函数的具体实现。

3、接下来,把csapp.c生成静态库libcsapp.a,它相当于main函数,这样可以直接使用,运行习题代码。

4、因为csapp.c中有关于线程的头文件,所以需要加上-lpthread,这个命令是使其连接csapp.h来调用csapp.c,来运行代码10-1.c,得出结果fd2 = 3。

 

posted @ 2015-11-08 18:58  bonjourvivi  阅读(202)  评论(0编辑  收藏  举报