20155304 《信息安全系统设计基础》第十三周学习总结

20155304 《信息安全系统设计基础》第十三周学习总结

第10章 系统级I/O

详细总结本章要点

  • 输入/输出(I/O)是在主存和外部设备之间拷贝数据的过程。输入操作是从I/O设备拷贝数据到主存,而输出操作是从主存拷贝数据到I/O设备。
  • 输入:从I/O拷贝到主存,输出:从主存拷贝到I/O
  • Unix IO(系统级IO)虽然是低级别的,但是了解它有助于理解其他的系统概念;而且有时候你只能使用Unix IO,比如网络编程。
  • Unix中所有的IO都被模型化为文件,输入输出则用读写文件来操作。

    10.1 Unix I/O

  1. 打开文件

-一个应用程序通过要求内核打开相应的文件

-描述符:内核返回一个小的非负整数

-定义常量:

  • STDIN_FILENO(描述符为0)
  • STDOUT_FILENO(描述符为1)
  • STDERR_FILENO(描述符为2)

2.改变当前的文件位置

  • 对于每个打开的文件,内核保持着一个文件位置k,初始为0
  • 应用程序能够通过执行seek操作显示设置文件的当前位置为k

3.读写文件

  • 一个读操作就是从文件拷贝n>0个字节到存储器,从当前文件位置k开始,然后将k增加到k+n
  • 写操作就是从存储器拷贝n>0个字节到一个文件,从当前文件k开始,然后更新k

4.关闭文件

  • 当应用完成了对文件的访问之后,他就通知内核关闭这个文件。
  • 一个Unix文件就是一个M个字节的序列:B0,B1,...B(m-1),所有的I/O设备都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行。
  • 这种将设备优雅的映射为稳健的方式,允许Unix内核引出一个简单、低级的应用接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行:打开文件、改变当前文件中位置、读写文件、关闭文件。

    10.2 打开和关闭文件

    打开文件

(1)进程是通过调用open函数打开一个已存在的文件或者创建一个新文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 int open(char *filename,int flags,mode_t mode) (若成功则返回新文件描述符,若出错为-1)

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

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

O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
O_CREAT:文件不存在,就创建新文件
O_TRUNC:如果文件存在,就截断它
O_APPEND:写操作前设置文件位置到结尾处

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

2.关闭文件:

  • 返回值:成功返回0,出错返回-1
  • 关闭一个已经关闭的描述符会出错
  • fd:即文件的描述符
#include <unisted.h>
 int close(int fd)(若成功则为0,若出错则为-1)

10.3 读和写文件

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

#include <unistd.h>
  ssize_t read(int fd, void *buf, size_t n);

2,。写文件:write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。

#include <unistd.h>
  ssize_t write(int fd, void *buf, size_t n);

3.通过调用lseek函数,应用程序可以显示地修改当前文件的位置。

4.某些情况下,read和write传送的字节比应用程序要求的要少,原因如下:

  • 读时遇到EOF(end of file)
  • 从终端读文本行
  • 读和写网络套接字
  1. ssize_t read(int fd, void *buf, size_t n);//0 EOF,-1 错误,n实际传送的字节数。
    ssize_t write(int fd, const void *buf, size_t n);// size_t是unsigned  ssize_t有符号
    /*ssize_t可以用来表示出错时必须返回的-1,但却使read值从4GB 减小到2GB*/
  • read函数从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf。返回值-1表示一个错误,而返回值0表示EOF。否则,返回值表示的是实际传送的字节数量。而write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。返回值要么为-1要么为写入的字节数目。
#include "csapp.h"

int main(void)
{
    char c;

    while(Read(STDIN_FILENO, &c, 1) != 0)
    Write(STDOUT_FILENO, &c, 1);
    exit(0);
}
  • 读和写网络套接字。可能会出现阻塞现象。

    实际上,除了EOF,在读磁盘文件时,将不会遇到不足值,而且在写磁盘文件时,也不会遇到不足值。然而,如果你想创建健壮的网络应用,就必须反复调用read和write处理不足值,直到所有需要的字节都传送完毕。

    10.4 用RIO包健壮地读写

    1.RIO包:健壮的包,会自动为你处理之前所述的不足值

2.RIO提供两种不同函数

(1)无缓冲的输入输出函数:这些函数直接在存储器和文件之间传送数据

  • 通过调用rio_readn和writen函数
  • 如果rio_readn和writen函数被一个从应用信号处理程序的返回中断,那么每个函数都会手动重启rio_readn或writen
#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);

(2)带缓冲的输入函数:这些函数允许你高效的从文件中读取文本行和二进制数据

  • 调用一个包装函数rio_readlineb,它从一个内部读缓冲区拷贝一个文本行,当缓冲区变空时,会自动地调用read重新填满缓冲区
  • 每打开一个描述符都会调用一次rio_readinitb函数
  • 对同一描述符,对rio_readlineb和rio_readnb的调用可以交叉进行,对这些带缓冲的函数的调用却不应和无缓冲的rio_readn函数交叉使用
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);

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

10.5 读取文件元数据

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

  • stat函数以一个文件名作为输入
  • stat函数以文件描述符作为输入
#include <unistd.h>
#include <sys/stat.h>
  int stat(const char *filename, struct stat *buf);
  int fstat(int fd,struct stat *buf);
  • 若成功,返回0,若出错则为-1.stat以一个文件名为输入,并且填充buf结构体。fstat函数只不过是以文件描述符而不是文件名作为输入。
struct stat {
#if defined(__ARMEB__)
    unsigned short st_dev;
    unsigned short __pad1;
#else
    unsigned long  st_dev;
#endif
    unsigned long  st_ino;
    unsigned short st_mode;
    unsigned short st_nlink;
    unsigned short st_uid;
    unsigned short st_gid;
#if defined(__ARMEB__)
    unsigned short st_rdev;
    unsigned short __pad2;
#else
    unsigned long  st_rdev;
#endif
    unsigned long  st_size;
    unsigned long  st_blksize;
    unsigned long  st_blocks;
    unsigned long  st_atime;
    unsigned long  st_atime_nsec;
    unsigned long  st_mtime;
    unsigned long  st_mtime_nsec;
    unsigned long  st_ctime;
    unsigned long  st_ctime_nsec;
    unsigned long  __unused4;
    unsigned long  __unused5;
}
  • 其中st_size成员包含了文件的字节大小。st_mode为文件访问许可位。UNIX提供的宏指令根据st_mode成员来确定文件的类型:S_ISREG(),这是一个普通文件么;S_ISDIR(),这是一个目录文件么;S_ISSOCK()这是一个网络套接字么。使用一下这个函数

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <unistd.h>
    int main()
    {
    int fd,size;
    struct stat buf_stat;
    memset(&buf_stat,0x00,sizeof(buf_stat));
    fd=stat("stat.c",&buf_stat);
        printf("%d\n",(int)buf_stat.st_size);
    return 0;
    }
  • Unix识别大量文件:普通文件(二进制或者文本);目录文件爱你(包含其他文件的信息);套接字(网络和其他进程通信)。

    10.6共享文件

(2)st_size成员包含了文件的字节数大小

(3)st_mode成员编码了文件访问许可位和文件类型

  • Unix提供的宏指令根据st_mode成员来确定文件的类型
宏指令:S_ISREG()   普通文件?二进制或文本数据
宏指令:S_ISDIR()   目录文件?包含其他文件的信息
宏指令:S_ISSOCK()  网络套接字?通过网络和其他进程通信的文件

10.6 共享文件

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

描述符表(descriptor table)每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项。

  • 文件表(file table) 打开文件的描述符表项指向问价表中的一个表项。所有的进程共享这张表。每个文件表的表项组成包括由当前的文件位置、引用计数(既当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的应用计数。内核不会删除这个文件表表项,直到它的引用计数为零。

v-node表(v-node table)同文件表一样,所有的进程共享这张v-node表,每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员。

  • 描述符1和4通过不同的打开文件表表项来引用两个不同的文件。这是典型的情况,没有共享文件,并且每个描述符对应一个不同的文件。

  • 多个描述符也可以通过不同的文件表表项来应用同一个文件。如果同一个文件被open两次,就会发生上面的情况。关键思想是每个描述符都有它自己的文件位置,所以对不同描述符的读操作可以从文件的不同位置获取数据。

  • 父子进程也是可以共享文件的,在调用fork()之前,父进程如第一张图,然后调用fork()之后,子进程有一个父进程描述符表的副本。父子进程共享相同的打开文件表集合,因此共享相同的文件位置。一个很重要的结果就是,在内核删除相应文件表表项之前,父子进程必须都关闭了他们的描述符。

10.7 I/O重定向

1.I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。

unix> ls > foo.txt

2.I/O重定向是依靠dup2函数工作的。dup2函数拷贝描述符表表项oldfd到描述符表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开,dup2会在拷贝oldfd之前关闭newfd。

int dup2(int oldfd,int newfd);

返回:若成功则为非负的描述符,若出错则为-1

10.8 标准I/O

1.应用程序可以通过open、close、lseek、read、write和stat这样的函数来访问Unix I/O。

  • RIO函数:read和write的健壮的包装函数,自动处理不足值,为读文本行提供一种高效的带缓冲的方法。
  • 标准I/O函数:提供了Unix I/O函数的一个更加完整的带缓冲的替代品,包括格式化的I/O例程。是磁盘和终端设备I/O之选。

2.套接字描述符:Unix对网络的抽象是一种称为套接字的文件类型,被称为套接字描述符。应用进程通过读写套接字描述符来与运行在其他计算机上的进程通信。

3.对流I/O限制是:

  • 跟在输出函数之后的输入函数,必须在其中间插入fflush、fseek、fsetpos或者rewind函数,后三个函数使用Unix I/O中的lseek函数来重置当前的文件位置。
  • 跟在输入函数之后的输出函数,必须在中间插入fseek、fsetpos或者rewind的调用,一个输出函数不能跟随在一个输入函数之后,除非该输入函数遇到了一个EOF。

4.解决对流I/O限制的方法:

  • 采用在每个输入操作前刷新缓存区这样的规则来满足。
  • 对同一个打开的套接字描述符打开两个流,一个用来读,一个用来写。
  • 对套接字使用lseek函数是非法的。
  • 在网络套接字上,使用RIO函数更常见。

5.标准I/O库(libc):高级输入输出函数

fopen/fclose:打开和关闭文件
fread/fwrite:读和写字节
fgets/fputs:读和写字符串
scanf/printf:复杂格式化的I/O函数

6.每个程序开始时都有三个打开的流:

stdin:标准输入
stdout:标准输出
stderr:标准错误

完成这一章所有习题

练习题10.1

open函数总是返回最低的未打开的描述符,所以第一次调用open会返回描述符3。调用close函数会释放描述符3.最后对open的调用会返回描述符3,因此程序的输出应该是fd2 = 3

练习题10.2

在本题中,fd1和fd2有独立的文件描述符,所以是典型的没有共享的打开文件方式

它们各自有各自的描述符表、文件表、v-code表,每个描述符对于foobar.txt都有它自己的文件位置,所以它们的读取是各自独立的,

从fd2的读操作会读取foobar.txt的第一个字节,因此最后得值是f,输出c = f

练习题10.3

本题中用的是子进程继承父进程打开文件的方式,Fork是子程序,和父程序共享同一个描述符表、文件表、v-code表,指向相同的文件

描述符fd在父子进程中都指向同一个打开文件表表项,子进程执行到Read(fd, &c, 1);时,子进程读取文件的第一个字节并且将文件位置加1

之后父程序在其基础上进行,读取下一个字符,是o,最后输出c = o

练习题10.4

要使重定向标准输入(描述符0)到描述符5,我们可以调用dup2(5,0)等价于dup2(5,STDIN_FILENO)

练习题10.5

题目所给的程序中与10.2、10.3最大的不同是增加了语句Dup2(fd2,fd1);

初始情况下fd1和fd2的描述符分别是3和4,所以是两个不同描述符表,指向两个不同的文件,但是由于在读了fd2一个字节之后,将fd1重定向到了fd2,所以此时再读fd1相当于在读fd2,也就是输出结果为c = o

上周考试错题总结

1.实验3中,在Ubuntu虚拟机中编译多线程程序时,gcc使用()选项

A .

-g

B .

-lthread

C .

-pthread

D .

-lpthread

正确答案: C 我的答案: A

解析:实际环境中只有-pthread可用

2.有关套接字接口函数open_clientfd()、open_listenfd(),下面说法正确的是()

A .

这两个函数中open_clientfd()只可以用于客户端编程

B .

这两个函数中open_clientfd()可以用于客户端和服务器端编程

C .

这两个函数中open_listenfd()只可以用于服务器端编程

D .

open_clientfd()中的port参数是客户端的端口

E .

open_clientfd()中的port参数是服务器端的端口

F .

open_clientfd()返回的clientfd可以有Unix I/O接口读写

G .

open_listenfd()返回的listenfd可以有Unix I/O接口读写

正确答案: A C E F 我的答案: B E G

解析:课本p660

3.有关socket 接口中的connect(),下面说法正确的是()

A .

这个函数用于客户端编程

B .

这个函数用于服务器端编程

C .

调用connect会发生阻塞,连接成功程序会继执行

D .

调用connect()成功返回的文件描述符可以用来数据传输

正确答案: A C D 你的答案: A

解析:课本p654

4.有关socket接口中的socket(),下面说法正确的是()

A .

不论客户端编程还是服务器端编程都要调用socket()

B .

socket()中的type参数设置为SOCK_STREAM时,基于TCP的,数据传输比较有保障

C .

socket()中的type参数设置为SOCK_DGRAM时,基于TCP的,数据传输比较有保障

D .

使用socket()返回的文件描述符通过read(),write()就可以传输数据了

E .

socket()中的protocol参数一般设为0

F .

socket()中的type参数设置为 SOCK_RAW ,允许对底层协议如IP或ICMP进行直接访问

G .

socket()可用getaddrinfo返回的ai_family,ai_socktype和ai_protocol填充

正确答案: A B E F G 我的答案: E F G

解析:课本p654

时间: 2024-10-11 16:09:47

20155304 《信息安全系统设计基础》第十三周学习总结的相关文章

20135223何伟钦—信息安全系统设计基础第十三周学习总结

学习任务: 1. 掌握三种并发的方式:进程.线程.I/O多路复用 2. 掌握线程控制及相关系统调用 3. 掌握线程同步互斥及相关系统调用 1.并发的意义 概念:只要逻辑控制流在时间上重叠,那么就可以称为并发. 意义: 访问慢速设备(如I/O设备):[CPU可以在这样的慢速中“腾出手”再去做其他事情,使自己保持“繁忙”.] 与人交互:每次用户进行某种操作的请求的时候[用户不会在意在自己进行操作的时候系统是否还处理着其他程序],一个独立的逻辑并发流被用来处理这个程序. 通过推迟工作来降低延迟 服务多

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

第11章 网络编程 所有的网络应用都是基于相同的基本编程模型有着相似的整体逻辑结构,并且依赖相同的编程接口. 网络应用依赖于很多在系统研究中已经学习过的概念,例如,进程.信号.字节器映射以及动态存储分配,都扮演着重要的角色. 我们需要理解基本的客户端-服务器编程模型,以及如何编写使用因特网提供的服务的客户端―服务器程序. 我们将把所有这些概念结合起来,开发一个小的但功能齐全的Web的服务器,能够为真实的Web,浏览器提供静态和动态的文本和图形内容. 11.1 客户端-服务器编程模型 1.每个网络

信息安全系统设计基础第十三周学习总结

第九章  虚拟存储器 一.虚拟存储器提供了三个重要能力: 1.将主存看作是一个存储在磁盘上的地址空间的高速缓存,在主存中只保护活动的区域,并根据需要在磁盘和主存之间来回传送数据: 2.为每个进程提供了一致的地址空间,从而简化了存储器管理: 3.保护了每个进程的地址空间不被其它进程破坏. 二.理解虚拟存储器的原因: 1.虚拟存储器是中心的:它是硬件异常.硬件地址翻译.主存.磁盘文件和内核软件的交互中心: 2.虚拟存储器是强大的:它可以创建和销毁存储器片.可以映射存储器片映射到磁盘某个部分等等: 3

20135205信息安全系统设计基础第十三周学习总结

第11章 网络编程 网络应用依赖于很多在系统研究中已经学习过的概念,例如,进程.信号.字节器映射以及动态存储分配,都扮演着重要的角色.还有一些新概念要掌握.我们需要理解基本的客户端-服务器编程模型,以及如何编写使用因特网提供的服务的客户端―服务器程序.最后,我们将把所有这些概念结合起来,开发一个小的但功能齐全的Web的服务器,能够为真实的Web,浏览器提供静态和动态的文本和图形内容. 11.1 客户端-服务器编程模型 每个人网络应用都是基于客户端-服务器模型的.才有陪你过这个模型,一个应用是由一

20135210程涵——信息安全系统设计基础第十三周学习总结

第12章 并发编程648 三种基本的构造并发程序的方法:进程.I/O多路复用.线程. 12.1 基于进程的并发编程 基于进程的并发服务器 关于进程的优劣 在父.子进程间共享状态信息,进程有一个非常清晰的模型:共享文件表,但是不共享用户地址空间.进程有独立的地址控件爱你既是优点又是缺点.由于独立的地址空间,所以进程不会覆盖另一个进程的虚拟存储器.但是另一方面进程间通信就比较麻烦,至少开销很高. 12.2 基于i/o多路复用的并发编程 I/O多路复用技术 基本思想:使用select函数,要求内核挂起

20135234马启扬-——信息安全系统设计基础第十三周学习总结

第十一章 网络编程 11.1 客户端-服务器编程模型 基本操作:事务 当一个客户端需要服务时,向服务器发送一个请求,发起一个事务. 服务器收到请求后,解释它,并以适当的方式操作它的资源. 服务器给客户端发送一个相应,并等待下一个请求. 客户端收到响应并处理它. 11.2 网络 (1)对主机而言:网络是一种I/O设备 从网络上接收到的数据从适配器经过I/O和存储器总线拷贝到存储器,典型地是通过DMA(直接存储器存取方式)传送. (2)物理上:网络是一个按照地理远近组成的层次系统 最底层:LAN(局

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

第九章 虚拟存储器 将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效地使用了主存.其实这一章还是讲解虚拟内存的,也就是和内核中的内存管理相关. 它为每个进程提供了一致的地址空间,从而简化了存储器管理 它保护了每个进程的地址空间不被其他进程破坏. 在硬件异常.汇编器.链接器.加载器.共享对象.文件和进程的设计中扮演着重要角色. 存储器让应用程序有了强大的能力,可以创建和销毁存储器片.将存储器片映射到磁盘文件的某个

信息安全系统设计基础第十三周学习总结-吕松鸿

第九章 虚拟存储器 虚拟存储器是计算机系统最重要的概念之一,它是对主存的一个抽象 三个重要能力: 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,高效的使用了主存 它为每个进程提供了一致的地址空间,从而简化了存储器管理 它保护了每个进程的地址空间不被其他进程破坏 9.1 物理和虚拟寻址 1.物理地址 计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组,每字节都有一个唯一的物理地址PA. 根据物理地址寻

20145216 史婧瑶《信息安全系统设计基础》第一周学习总结

20145216 <信息安全系统设计基础>第一周学习总结 教材学习内容总结 Linux基础 1.ls命令 ls或ls .显示是当前目录的内容,这里“.”就是参数,表示当前目录,是缺省的可以省略.我们可以用ls -a .显示当前目录中的所有内容,包括隐藏文件和目录.其中“-a” 就是选项,改变了显示的内容.如图所示: 2.man命令 man命令可以查看帮助文档,如 man man : 若在shell中输入 man+数字+命令/函数 即可以查到相关的命令和函数:若不加数字,那man命令默认从数字较

20145311 《信息安全系统设计基础》第一周学习总结

20145311 <信息安全系统设计基础>第一周学习总结 教材学习内容总结 常用的部分命令 CTRL+SHIFT+T:新建标签页,编程时有重要应用: ALT+数字N:终端中切换到第N个标签页,编程时有重要应用: Tab:终端中命令补全,当输入某个命令的开头的一部分后,按下Tab键就可以得到提示或者帮助完成: CTRL+C:中断程序运行 Ctrl+D:键盘输入结束或退出终端 Ctrl+S: 暂定当前程序,暂停后按下任意键恢复运行 Ctrl+A: 将光标移至输入行头,相当于Home键 Ctrl+E