进程程序替换的使用场景:
-
守护进程 (服务24小时不间断运行)
基本具备的条件: server可执行程序, 守护进程的程序,
认知: 守护进程是由守护程序启动的, 在守护进程这个程序当中使用到了进程程序替换 + 创建子进程 + 进程间通信(判断子进程是否运行正常)
守护进程创建出一个子进程, 让子进程程序替换为server可执行程序, 两个程序之间通过进程间通信来进行进程通信,守护体现在:
- 创建子进程 + 进程间通信
- 每隔一段时间获取一下子进程状态(时间),
- 守护进程去获取状态, 若server可执行程序时间在修改 则证明server正常,
- 若发现server可执行程序并没有发生更改, 则认为server可执行程序状态异常;
异常执行策略: 重新创建子进程, 让子进程程序替换, 替换为新的server可执行程序
server可执行程序:
. 通过进程间通信方式, 每隔一段时间告诉父进程当前的状态,但守护程序只是一个治标不治本的方法, 因为如果server可执行程序当中, 代码写的比较烂, 时不时就崩溃, 守护进程并不能根治server程序崩溃的问题(这个问题需要程序员更改代码了)
-
分布式部署:
客户端想来访问服务端, 同样一个server可执行程序可以在多台机器上部署, 假设现在有三个server程序在不同的机器上(而不同的机器上跑的是相同的服务), 当客户端发起请求后, 先到代理, 代理决定把请求分发给哪一个server程序; 代理会先去尝试连接server程序, 如果连接不上, 就不会再去向那个连接不上的程序转发请求了, 而转发给其他server程序, 这一系列的操作就是通过分布式部署来完成的
若有一个server端崩溃掉了, 代理就会把请求转发到其他server端,
nginx: 反向代理器 -
shell终端
shell终端用 echo $BASH可查看 /usr/bin/bash, 是一个可执行程序, 写的命令(也是一可执行程序)就是和这个bash启动的进程打交道
3.1 启动bash可执行程序
3.2 当用户输入命令(可执行程序)的时候或者自己写一个文件在运行的时候, bash会创建一个子进程, 子进程程序替换为我们所写的可执行程序(./mytest就是告诉要被替换的这个可执行程序在哪里)
3.3 在子进程程序替换的时候, 如果是前台进程(mytest), 则bash负责进程等待, 不能接受命令
用下图的时间轴来表示事件的发生次序。其中时间从左向右。shell由标识为sh的方块代表,它随着时间的流逝从左向右移动。shell从用户读入字符串"ls"。shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束
然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序, 并等待这个进程结束。
测试: minishell
- 从标准输入当中读取数据(要执行的可执行程序) fgets(), 先将读入的数据放入字符数组, 第一步先将字符数组全部清空(初始化为’\0’), 再读取数据.
用fgets从键盘读取数据, gets()存在一个问题(bug), 并不会控制往字符数组当中读多少数据, 可能会造成越界,
fgets(buf, sizeof(buf), stdin); 读到NULL, 则认为读取失败,
若后面要执行printf("%s\n", buf) , 从buf当中读取数据时, 由于C语言中判定字符串的结束标志是’\0’, 如果buf里面是满的, 由于未遇到’\0’, printf在读取数据时会访问到buf外, 访问未知. 造成内存越界,
因此, 通常给sizeof(buf)后-1, 这样的话, 读的时候只读取sizeof(buf) -1的数据, 最后一个位置预留了’\0’的位置, 就不会出现内存越界的问题了. - 拆分可执行程序名称和命令行参数(原则: 我们认为从标准输入当中读取到的内容第一个空格之前的数据是可执行程序的名称) 第一个空格之后的都认为是命令行参数 (ls -a)
- 创建子进程 子进程程序替换可执行程序
- 在子进程程序替换的时间内, 让父进程等待
isspace函数
判断一个字符是否有空白字符(空格, 换页符, 换行, 回车, 水平制表符, 垂直制表符)
返回值: 返回非0为读到了空白字符, 返回0 则为没有读到
如果子进程陷入死循环(替换失败) exit(0)执行不了, 一直创建子进程, 父进程继续等待,调用waitpid(), 都在阻塞,
不杀他 父进程在waitpid, 子进程在读, 下一次上次的pid又进行waitpid, 新的子进程又去读fgets(), 子子孙孙无穷, 最终会把操作系统资源消耗完
minishell总结:
1. 融合进程创建, 进程等待, 进程程序替换等知识
2. bash本身也是一个程序, 是在操作系统启动之初就启动的程序, 输入的所有命令都是和bash沟通的. 可以推测出ls. pwd, cd.. 等linux命令都是可执行程序
3. 实现
3.1 需要从标准输入中获取用户输入的命令
3.2 需要创建子进程 让子进程程序替换执行刚刚从标准输入当中读取的命令
3.3 父进程需要在子进程替换的时候进行进程等待, 防止子进程成为僵尸进程