2017-2018-20155336 《信息安全系统设计基础》第六周学习总结
学习目标
- 了解异常及其种类
- 理解进程和并发的概念
- 掌握进程创建和控制的系统调用及函数使用:fork,exec,wait,waitpid,exit,getpid,getppid,sleep,pause,setenv,unsetenv,
- 理解数组指针、指针数组、函数指针、指针函数的区别
- 理解信号机制:kill,alarm,signal,sigaction
- 掌握管道和I/O重定向:pipe, dup, dup2
教材学习内容总结
第八章
异常
- 异常就是控制流中的突变,用来响应处理器状态中的某些变化
异常处理
-
系统中可能的每种类型的异常都分配了一个唯一的非负整数的异常号。
-
处理器:被零除、缺页、存储器访问违例、断点以及算术溢出
-
操作系统:系统调用和来自外部I/O设备的信号
异常的类别
-
中断 :来自I/O设备的信号,异步,总是返回到下一条指令
-
陷阱 :有意的异常,同步,总是返回到下一条指令
-
故障 :潜在可恢复的错误,同步,可能返回到当前指令
-
终止 :不可恢复的错误,同步,不会返回
进程
-
异常是允许操作系统提供进程的概念所需要的基本构造块。
- 进程:一个执行中的程序的实例。上下文是由程序正确运行所需要的状态组成的,这个状态包括存放在存储器中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
-
进程提供给应用程序的关键抽象:
- 一个独立的逻辑控制流,独占地使用处理器;
- 一个私有的地址空间,独占地使用存储器系统。
并发流
- 并发流:一个逻辑流的执行在时间上与另一个流重叠。
并发:多个流并发地执行的一般现象。
多任务:一个进程和其他进程轮流运行的概念。
时间片:一个进程执行它的控制流的一部分的每一时间段。
多任务也叫时间分片。
- 并行流:如果两个流并发的运行在不同的处理器核或者计算机上。
创建和终止进程
- 进程总处于三种状态
(1)运行:进程要么在CPU上执行,要么在等待被执行且最终会被内核调度。
(2)停止:程序的执行被挂起,,且不会被调度。
(3)终止:进程用永远停止了。
- 终止原因:
(1)收到一个信号,默认行为是终止进程
(2)从主进程返回
(3)调用exit函数
-
父进程通过调用fork函数创建一个新的运行的子进程。
-
子进程和父进程的异同:
-
异:有不同的PID
-
同:用户级虚拟地址空间,包括:文本、数据和bss段、堆以及用户栈。任何打开文件描述符,子进程可以读写父进程中打开的任何文件。
-
fork函数: 因为父进程的PID总是非零的,返回值就提供一个明确的方法来分辨程序是在父进程还是在子进程中执行。
- fork函数的特点:
(1)调用一次,返回两次
(2)并发执行
(3)相同的但是独立的地址空间
(4)共享文件
回收子进程
-
当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程。
一个终止了但还未被回收的进程称为僵死进程。 -
一个进程可以通过调用waitpid函数来等待它的子进程终止或者停止。
#include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid,int *status,int options); //返回:若成功,返回子进程的PID;若WNOHANG,返回0;若其他错误,返回-1。
默认地,当option=0时,waitpid挂起调用进程的执行,直到它的等待集合中的一个子进程终止。
-
判定等待集合的成员
有参数pid来确定的:
(1)pid>0:等待集合是一个单独的子进程,进程ID等于pid。
(2)pid=-1:等待结合就是由父进程所有的子进程组成的。
-
修改默认行为
通过options设置:
(1)WNOHANG:默认行为是挂起调用进程。(2)WUNTRACED:默认行为是只返回已终止的子进程。
(3)WNOHANG|WUNTRACED:立即返回,如果等待集合中没有任何子进程被停止或者已终止,那么返回值为0,或者返回值等于那个被停止或者已经终止的子进程的PID。
-
检查已回收子进程的退出状态
wait.h头文件定义了解释status参数的几个宏:
(1)WIFEXITED:如果子进程通过调用exit或者一个返回正常终止,就返回真;
(2)WEXITSTATUS:返回一个正常终止的子进程的退出状态。只有在WIFEXITED返回真时,才会定义这个状态。
-
错误条件
(1)若调用进程没有子进程,那么waitpid返回-1,并且设置errno为ECHILD;
(2)若waitpid函数被一个信号中断,那么返回-1,并设置errno为EINTR
wait函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
//返回:若成功,返回子进程的PID;若错误,返回-1。
调用wait(&status)等价于调用waitpid(-1.&status,0)
让进程休眠
sleep函数:将进程挂起一段指定的时间
#include <unistd.h>
unsigned int sleep(unsigned int secs);
//返回:还要休眠的秒数
如果请求的时间量已经到了,返回0,否则返回还剩下的要休眠的秒数。
pause函数:让调用函数休眠,直到该进程收到一个信号。
#include <unistd.h>
int pause(void);
//返回:总是-1
加载并运行程序
execve函数:在当前进程的上下文中加载并运行一个新程序。
#include <unistd.h>
int execve(const char *filename,const char *argv[],const char *envp[]);
//返回:若成功,则不返回,若错误,返回-1
filename:可执行目标文件
argv:带参数列表
envp:环境变量列表
特点:execve调用一次从不返回
getenv函数:在环境数组中搜素字符串“name =VALUE”,若找到了,就返回一个指向value的指针,否则它就返回NULL。
#include <stdlib.h>
char *getenv(const char *name);
//返回:存在,返回指向name的指针,若无匹配的,为NULL
**注意:**
execve函数在当前进程的上下文中加载并运行一个新的进程。它会覆盖当前进程的地址空间,并没有创建一个新的进程,新的进程仍然有相同的PID,并且继承了调用execve函数时已打开的所有文件描述符。
eval函数:对外壳命令行求值
parseline函数:解析外壳的一个输入
指针数组:指针的数组,这个数组里全是指针。
数组指针:是一个指针,这个指针指向数组。
函数指针:同理也是一个指针,指向一个函数,是一个变量。
指针函数:带指针的函数,但本质是一个函数。
信号
-
Unix信号:更高层的软件形式的异常,允许进程中断其他进程
-
P505:30种不同类型的信号表
信号术语
-
发送信号:
1)内核检测到一个系统事件2)一个进程调用了kill函数
-
接收信号:当目的进程被内核强迫以某种方式对发送的信号作出反应时,目的进程就接收了信号
-
待处理信号:一个只发出而没有被接收的信号
- 发生信号的函数: kill()、raise()。
- 捕捉信号的函数: alarm()、pause()。
- 捕捉信号的函数: alarm()、pause()。
kill:
- kill()函数不仅可以终止进程(实际上是通过发出SIGKILL信号终止),也可以向进程发送其他信号。
alarm:
- 也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间到时,它就向进程发送SIGALARM信号。要注意的是,一个进程只能有一个闹钟时间,如果在调用alarm()之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。
signal()、sigaction()
- linux主要有两个函数实现信号的安装:signal()、sigaction()。其中signal()只有两个参数,不支持信号传递信息,主要是用于前32种非实时信号的安装;而sigaction()是较新的函数(由两个系统调用实现:sys_signal以及sys_rt_sigaction),有三个参数,支持信号传递信息,主要用来与 sigqueue() 系统调用配合使用,当然,sigaction()同样支持非实时信号的安装。sigaction()优于signal()主要体现在支持信号带有参数。
第十章
-
输入/输出(I/O)是在主存和外部设备之间拷贝数据的过程。 输入操作:从I/O设备拷贝数据到主存、输出操作:从主存拷贝数据到I/O设备
-
Unix I/O是一个简单低级的应用接口,可以把所有的输入输出当作对文件的读写来执行。
- 打开文件:标准输入描述符为0、标准输出描述符为1、标准错误描述符为2.
- 改变当前的文件位置:文件位置是从文件开头起始的字节偏移量。
- 读写文件:从当前文件位置开始。当大于文件长度的时候出发EOF条件。
- 关闭文件。
-
open函数int open(char *filename,int flags,mode_t mode);
-
flages参数指明进程打算如何访问该文件O_RDONLY:只读、O_WRONLY:只写、O_RDWR:可读可写``O_CREAT:如果文件不存在就创建一个截断的(空)文件、O_TRUNC:如果文件已经存在,就截断它。、O_APPEND:每次写操作前,设置文件位置到文件的结尾处。
-
mode参数指定新文件的访问权限位,每个进程都有一个umask,是通过调用umask函数来设置的。当进程通过带某个mode参数的open函数调用来创建一个新文件时,文件的访问权限位被设置为mode & ~umask
- 进程通过调用close函数关闭一个打开的文件:
int close(int fd);
- 进程通过调用close函数关闭一个打开的文件:
-
read函数:从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf,返回值-1表示错误,返回值0表示EOF。
- read和write传送的字节一般比应用程序要求的少,不足值产生的情况有:
- 读时遇到EOF
- 从终端读文本行
- 读和写网络套接字
-
-
RIO包可自动处理不足值。 ssize_t rio_readn(int fd,void *usrbuf,size_t n);
- 无缓冲的输入输出函数:直接在存储器和文件之间传送数据。
- 带缓冲的输入函数:允许从文件中读取文本行和二进制数据,文件内容缓存在应用级缓冲区内。
-
应用程序通过调用statint stat(const char *filename,struct stat *buf);和fststint fstat(int fd,struct stat *buf);
-
函数检索关于文件的信息。
教材学习中的问题和解决过程
-
关于系统及I/O的知识点:
在之前几章的学习都有所接触问题总的不大,但是在10.2中关于打开和关闭文件的open函数中的第三个参数的使用存在问题。书上p597写了 一个例子,文件的拥有者有读写权限,而其他的用户都有读权限。而答案为什么给出的是umask(DEF _ UMASK);fd = Open ("foo.txt",O _CREATE|O _TRUNC|O _WRONLY,DEF _MODE);给出的O _WRONLY是只读,而并不是读写操作,是如何完成的读写操作? 而其也具体的权限参数是什么?根据上面的解释知道是Open函数的第二个flags参数是指明了进程打算如何访问这个文件,第三个mode _t mode参数是指明文件的访问权限,结合图10—1会知道具体的访问权限。后来通过看书,发现自己忽略掉了一点就是每个进程都有一个 umask,它是通过调用umask函数来设置的。这样以来之前对于这个答案有所定义给定了mode和umask默认值: #define DEF _MODE S _IRUSR|S _IWUSR|S _IRGRP|S _ IWGRP|S _IROTH|S _IWOTH #define DEF _UMASK S _IWGRP|S _IWOTH,这样在结合之前的 Open函数就解决了我的问题。
代码调试中的问题和解决过程
-
在完成练习题10.1时候出现了问题
通过查询csapp.h是是一堆头文件的打包,linux应该没有自带csapp.h。于是更改了头文件,编译成功。
-
man k 命令的使用
代码托管
心得体会
本周的知识点较上周多一些,代码的量的理解也大了许多,但是在周末之前就开始学习了,整体来说时间相对宽裕一些。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 600/1300 | 4/9 | 30/90 | |
第五周 | 650/1300 | 5/9 | 40/90 | |
第六周 | 700/1300 | 6/9 | 50/90 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:10小时
-
实际学习时间:10小时
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)