掀浪云网站建设,网站建设技术分类,商务网官网,从化网站开发公司目录
前言#xff1a;
1 程序替换原理
2 单进程替换
3 替换函数
3.1 函数使用
4 程序去替换自己的另一个程序操作方式 5 实现自己的shell 前言#xff1a; 通过我们之前对于子进程的应用#xff0c;我相信大家一定是能够想到创建子进程的目的之一就是为了代劳父进程执…目录
前言
1 程序替换原理
2 单进程替换
3 替换函数
3.1 函数使用
4 程序去替换自己的另一个程序操作方式 5 实现自己的shell 前言 通过我们之前对于子进程的应用我相信大家一定是能够想到创建子进程的目的之一就是为了代劳父进程执行父进程的部分代码也就是说本质上来说父子进程都是执行的同一个代码段的数据在子进程修改数据的时候进行写时拷贝修改数据段的部分数据。 但是还有一个目的大家知道吗不知道没关系因为这就是本篇文章的主题将子进程在运行时指向一个全新的程序代码也就是我们的进程程序替换。
1 程序替换原理 首先程序替换是将当前进程的全部数据被替换成为了另外的一个程序的代码再运行那么这样做产生了一个什么样的效果那就是我们没有必要对一个已经出现的程序再次的写一遍以及不用在PCB数据结构当中再添加一个新的PCB块。如下图所示 从上图当中我们可以知道一个进程的出现必须先在PCB结构当中先构建自己的PCB块有了对应的虚拟地址之后然后虚拟地址通过页表映射的方式在物理地址当中找到位置然后将磁盘当中的程序加载进入对应的物理地址。 我们进程替换所做的事情就是不改变PCB的情况之下后续的操作重新做了一遍也就是说操作系统在这一块进行了全面的写实拷贝连代码段的数据都被修改了。保证了代码的独立性。
2 单进程替换 只看上面的解释我相信小伙伴们对于这一块还是不太理解那么上代码 7 int main()8 {9 printf(begin---\n);10 execl(/bin/ls,ls,-a,-l,NULL);11 printf(end----\n);12 return 0;13 }我们可以看到我们主程序当中写下了两个printf分别在execl函数的前后execl里面有我们熟悉的指令程序也就是ls先不管execl是什么先观察效果。 发现了什么我们在execl后面的printf没有被输出也就证明了我们的程序替换是完全替换会将我们的代码完全变为另外一个程序的代码。
3 替换函数 #include unistd.h int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg, ...,char *const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); 由我们库封装的exec函数常用的有上面的几种这些函数都有下面的特性当该函数成功执行那么进程替换成功代码不再返回如果函数调用失败例如不正确的地址不正确的文件等等函数会返回一个-1并且exec函数之后在函数调用失败时才有返回值成功没有返回值。 只有失败时有返回值其实很好理解因为函数调用成功那就表示程序替换成功原来的代码都被替换了我返回之后给谁没了之后的代码就是新代码了。
3.1 函数使用 使用这些函数其实简单先将函数名的exec提取出来看后面的几个字母。 l表示用列表方式传递。 其中/bin/ls表示需要执行的文件是谁ls表示执行方式而-a和-l表示这个执行的参数列表。 v表示使用数组的方式传递。 可以看到我们用过指针数组的方式将我们的执行和参数列表存到了一起然后将这个指针数组作为参数传递给我们的execv函数就行。 p表示自己只需要传递需要执行的文件是谁操作系统会从默认环境变量当中去查找。 e表示可以传递自己的环境变量。 注意当我们传递自己的环境变量时会替换默认环境变量所以如果想要添加一个环境变量而不是替换那就需要下方的操作。 通过系统提供的存环境变量的environ变量在用putenv函数添加自己的环境变量以达到添加环境变量的操作。 上面的几个字母通过不同的组合可以达到不同的操作方式。
4 程序去替换自己的另一个程序操作方式 7 int main()8 {9 pid_t id fork(); 10 if(id 0)11 {12 extern char** environ;13 printf(begin\n);14 printf(begin\n);15 printf(begin\n);16 printf(begin\n);17 printf(我是子进程PID是%d\n,getpid());18 char arg[] MYENVYou Can See Me;19 putenv(arg);//替换程序在exec目录下执行文件名字是otherproc20 execle(./exec/otherproc,otherproc,NULL,environ); 21 printf(end\n); 22 printf(end\n); 23 printf(end\n); 24 printf(end\n); 25 exit(1); 26 } 27 28 sleep(2); 29 int status 0; 30 waitpid(id,status,0); 31 printf(我是父进程,PID是%d子进程退出状态是%d\n,getpid(),WEXITSTATUS(status)); 32 33 return 0;34 }我们需要从原程序中替换到这个otherproc这个执行文件。 使用函数execle(./exec/otherproc,otherproc,NULL,environ); 5 实现自己的shell 通过上面的学习相信大家对进程替换已经有了足够的了解了那么大家有没有想过我们的Linux通过shell是怎么运行的呢我们都知道我们创建的所有进程都是bash的子进程那么我们是不是也可以写一个自己的bash然后可以使用这些指令呢答案是可以请看下方代码。 1 #include stdio.h2 #include unistd.h3 #include sys/types.h4 #include wait.h5 #include string.h6 #include assert.h7 #include stdlib.h8 9 #define MAX_STR 102410 #define ARG 6411 #define SPE 12 13 int splite(char commandstr[], char* argv[])14 {15 assert(commandstr);16 assert(argv);17 argv[0] strtok(commandstr,SPE);18 if(argv[0] NULL) return -1;19 20 int i 1;21 while((argv[i] strtok(NULL,SPE)));22 23 return 0;24 }25 26 void show_command(char* argv[]) 27 {28 int i 0;29 while(argv[i] ! NULL)30 {31 printf(%d,%s ,i,argv[i]);32 i;33 }34 printf(\n);35 }36 37 int main()38 {39 while(1) 40 {41 //接收从界面接收的字符数组42 char commandstr[MAX_STR] {0};43 44 //将我们的命令通过空格的方式切割成为一个一个的字符串45 //第一个是我们的指令后续的是参数列表46 char* argv[ARG] {NULL};47 48 //我们的shell界面提示49 printf([zhangshanmymachine test ]# );50 51 //因为我们希望直接看到上面的打印而不是等缓冲区运行完毕52 fflush(stdout);53 54 //将输入的字符获取并赋值给commandstr数组当中55 char* s fgets(commandstr,sizeof(commandstr),stdin);56 assert(s);57 58 //因为s这个变量我们并没有实际的使用所以用一个不会做任何改变的操作使用59 (void)s;60 61 //我们输入指令时回安回车表示输入完毕而我们不希望操作系统录入这个\n所以需要更改62 commandstr[strlen(commandstr)-1] \0;63 64 //将字符切割成为小字符串然后赋值给argv这个指针数组当中65 int n splite(commandstr,argv);66 show_command(argv); 67 //如果没有获取有效的命令直接跳过本次循环也就是指令失效68 if(n ! 0) continue;69 70 //创建子进程用于后续的程序替换71 //因为程序替换需要完全替换后续的代码也就是说如果用父进程去替换72 //就不会有下一次的循环了这不是我们期望的结果所以建子进程73 pid_t id fork();74 75 if(id 0)76 {77 //通过有默认路径查询目录加上指针数组的方式exec方式进行进程程序替换78 execvp(argv[0],argv);79 //替换之后是不应该被执行的如果执行了则表示程序替换错误80 exit(1);81 }82 int status 0;83 84 //只是回收子进程的退出信息没有其余的操作所以不用WNOHANG也没有后续的代码85 waitpid(id,status,0);86 }87 }该代码有很多细节但是博主也不打算过多的解释了因为博主已经在主程序的每一句话都写了注解如果大家有兴趣可以自行阅读难度不大。
运行结果 以上就是博主对于进程替换的全部理解了希望能够帮到大家。