找出全书你认为最重要的一章,深入重新学习一下,要求(期末占10分):
完成这一章所有习题
详细总结本章要点
给你的结对学习搭档讲解你的总结并获取反馈
参考上面的学习总结模板,把学习过程通过博客(随笔)发表,博客标题“学号 《信息安全系统设计基础》第十三周学习总结”,博客(随笔)要通过作业提交。
教材内容总结
这次学习的是教材第10章的内容:
(一)Unix IO概述
所有的IO设备,如网络、磁盘和终端,都被模型化为文件,(一个Unix文件就是一个m个字节的序列),而所有的输入和输出都被当做对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许Unix内核引出一个简单、低级的应用接口,称为Unix IO:
打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个IO设备。内核返回一个小的非负整数,叫做描述符。内核记录有关这个打开文件的所有信息,应用程序只需要记住这个描述符。(Unix外壳创建的每个进程开始时都有三个打开的文件:标准输入STDIN_FILENO=0;标准输出STDOUT_FILENO=1;标准错误STDERR_FILENO=2)。
改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始化为0。应用程序可以通过seek操作,显式地设置文件的当前位置k。
读写文件。给定一个大小为m字节的文件,当k≥m时执行读操作会触发一个称为end-of-file(EOF)的条件,应用程序可以检测此条件,而文件结尾处并没有“EOF符号”。
关闭文件。内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止时,内核都会关闭所有打开的文件并释放它们的存储器资源。
(二·一)打开和关闭文件
int open(char *filename, int flags, mode_t mode);
int close(int fd);
对于open来说,返回的描述符总是在进程中当前没有打开的最小描述符。
flags指明进程如何访问文件:O_RDONLY:只读;O_WRONLY:只写;O_RDWR:读写
flags也可以提供一个其他掩码,为写提供一些提示:,O_CREAT:如果文件不存在,创建空文件;O_TRUNC:如果文件存在,清空;o_APPEND:添加
mode指定新文件的访问权限;每个进程都有一个umask,可以通过umask函数设置;当open一个新文件时,其访问权限为:mode & ~umask
关闭一个已经关闭的描述符会出错。
二·二)读写文件
read函数从描述符fd的当前位置拷贝最多n个字节到存储器位置buf,返回-1表示一个错误;返回0表示EOF;否则,返回实际传送值。
write函数从存储器位置buf拷贝至多n个字节到fd的当前位置。
可以调用lseek函数,显式地修改当前文件位置
我们注意到read和write当中,传送的字节都是至多为n,那么什么时候会小于n呢?也就是不足值(short count)出现的情况:
读时遇到EOF。若文件20个字节,n=50;那么第一个read返回不足值20;第二个read返回0发出EOF信号;
从终端读文本行。如果fd与终端相关联(如键盘和显示器),那么每个read函数将一次传送一个文本行,返回的不足值等于文本行大小;
读和写网络套接字。内部缓冲约束和较长的网络延迟会引起read和write返回不足值。如果想创建健壮的web服务器应用,必须反复调用read和write处理不足值,直到所有需要的字节都传送完毕。
(三)RIO包健壮地读写
为自动处理不足值情况,我们构造一个健壮的IO函数。
RIO函数分两类:
无缓冲的输入输出函数:对网络中读写二进制数据尤其有用;
带缓冲的输入函数:可以高效地从文件中读取文本行和二进制数据。其中带缓冲的RIO输入函数是线程安全的。
假设我们要编写一个程序来计算文本文件中文件行的数量该如何实现?
一种方法是read函数一次读取一个字节,检查是否有换行符。缺点是:效率不高,因为每读一个字节就要陷入一次内核。
更好地方法是调用一个包装函数(rio_readlineb),从一个内部读缓冲区拷贝一个文本行,当缓冲区为空时,再自动调用read重新填满缓冲区。
对于既然文本行也包含二进制数据的文件,我们也提供一个rio_readn带缓冲区版本:rio_readnb。
总结:带缓冲区的rio函数是为了效率;不带缓冲区的roio_readn和rio_writen是为了健壮性
(四)读取文件的元数据
(五)内核是如何打开文件的?
课后习题
10.1
结果是fd=3
10.2
c=f
10.3
c=0
10.6
程序的输出应该是什么?
输出 fd2 = 4
已经有0 1 2被打开,fd1是3,fd2是4,关闭fd2之后再打开,还是4。
10.7
int main(int argc, char **argv)
{
int n;
rio_t rio;
char buf[MAXBUF];
Rio_readinitb(&rio, STDIN_FILENO);
while((n = Rio_readnb(&rio, buf, MAXBUF)) != 0)
Rio_writen(STDOUT_FILENO, buf, n);
}
10.8
只需要将stat那句话改为: fstat(atoi(argv[1]), &stat);
当然,如果需要加其他处理的话(比如判断参数对错,fd是否存在等等),还需要添加一些语句。
10.9
这里应该是表明,输入重定向到了foo.txt,然而3这个描述符是不存在的。
说明foo.txt并没有单独的描述符3。
所以Shell执行的代码应该是这样的:
if (Fork() == 0) {/* Child */
int fd = open("foo.txt", O_RDONLY, 0);
dup2(fd, 1);
close(fd);
Execve("fstatcheck", argv, envp);
}
10.10
这里使用一个重定向的技术即可。如果参数个数为2,那么就将标准输入重定向到文件。
程序并没有检测各种错误。
int main(int argc, char **argv)
{
int n;
rio_t rio;
char buf[MAXLINE];
if(argc == 2){
int fd = open(argv[2], O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
close(fd);
}
Rio_readinitb(&rio, STDIN_FILENO);
while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
Rio_writen(STDOUT_FILENO, buf, n);
}
学习与感悟
本周主要学习代码的部分,经过自己的探索了解了每个代码的具体含义,并把每个代码都进行了实际操作,达到了正确的结果,不足之处在于细节上还不是很理解,还需要慢慢消化
学习进度条
代码行数(新增/累积)| 博客量(新增/累积)|学习时间(新增/累积)|重要成长 |
| -------- | :----------------😐:----------------😐:---------------: |:-----: |
| 目标 | 5000行 | 30篇 | 400小时 | |
| 第一周 | 10 /10 | 1/1 | 10/10 | |
| 第二周 | 40 /70 | 2/4 | 18/38 | |
| 第三周 | 150/200 | 3/7 | 15/60 | |
|第四周 | 160/210 |6/8| 23/70
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
参考:软件工程软件的估计为什么这么难,软件工程 估计方法
计划学习时间:20小时
实际学习时间:23小时
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)
参考资料
《深入理解计算机系统V3》学习指导