首页
最新活动
服务器租用
香港服务器租用
台湾服务器租用
美国服务器租用
日本服务器租用
新加坡服务器租用
高防服务器
香港高防服务器
台湾高防服务器
美国高防服务器
裸金属
香港裸金属服务器
台湾裸金属服务器
美国裸金属服务器
日本裸金属服务器
新加坡裸金属服务器
云服务器
香港云服务器
台湾云服务器
美国云服务器
日本云服务器
CDN
CDN节点
CDN带宽
CDN防御
CDN定制
行业新闻
官方公告
香港服务器资讯
帮助文档
wp博客
zb博客
服务器资讯
联系我们
关于我们
机房介绍
机房托管
登入
注册
帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
联系客服
服务器资讯
/
香港服务器租用
/
香港VPS租用
/
香港云服务器
/
美国服务器租用
/
台湾服务器租用
/
日本服务器租用
/
官方公告
/
帮助文档
【Linux】进程的程序替换
发布时间:2024-02-27 20:53:47 分类:帮助文档
【Linux】进程的程序替换 文章目录 1. 程序替换1.创建子进程的目的是什么?2.了解程序是如何进行替换的3. 程序替换的基本原理当创建进程的时候,先有进程数据结构,还是先加载代码和数据?程序替换是整体替换,不是局部替换execl 返回值 4. 替换函数1. execl2. execv3. execlp4. execvp5. execle 2. 自定义shell缓冲区问题fgets 使用出现空格问题完整代码动图演示 1. 程序替换 1.创建子进程的目的是什么? 目标:为了让子进程帮父进程执行特定的任务 具体做法:1. 让子进程执行父进程的一部分代码 红框中的代码实际上是父进程的代码,在没有执行fork之前代码就有了,在没有创建子进程之前,父进程的代码加载到内存了,子进程被创建出来是没有独立的代码,这个代码是父进程的代码,父进程通过if判断分流让子进程去跑了 2.创建一个子进程不执行父进程的代码,而是让子进程在磁盘当中执行全新的程序,这种操作称之为进程的程序替换 2.了解程序是如何进行替换的 程序替换函数 execl 输入 man execl 查看程序替换接口 int execl(const char *path, const char *arg, …); 括号内部的 . . . 称为 可变参数列表,可以给c函数传递任意个数的参数 第一个参数为 要执行什么命令 第二个参数 为 要怎样执行程序 最后以NULL结尾表示参数传完了 创建test.c文件并输入以下内容 #include
#include
#include
int main() { printf("begin......\n"); printf("begin......\n"); printf("begin......\n"); printf("begin......\n"); execl("/bin/ls", "ls", "-a", "-l", NULL); printf("end........\n"); printf("end........\n"); printf("end........\n"); printf("end........\n"); } 运行可执行程序发现,只有begin 以及执行 ls -l -a显示的指令 再次修改test.c文件内容如下 #include
#include
#include
int main() { printf("begin......\n"); printf("begin......\n"); printf("begin......\n"); printf("begin......\n"); printf("我已经是一个进程啦,我的PID:%d\n",getpid()); execl("/bin/ls", "ls", "-a", "-l", NULL); printf("end........\n"); printf("end........\n"); printf("end........\n"); printf("end........\n"); } test.c 经过编译形成mytest可执行程序,./可执行程序就变成进程了,CPU调度进程 ,打印出代码中的打印语句,同时调用程序替换execl,将ls程序执行起来了 [yzq@VM-8-8-centos nn]$ file /bin/ls /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=c8ada1f7095f6b2bb7ddc848e088c2d615c3743e, stripped 使用的 /bin/ls 命令 实际上是一个可执行程序,所以ls程序是在磁盘上的 前面执行的是自己代码的一部分,当调用execl时,将磁盘中可执行程序替换当前进程的代码和数据 后半部分就不执行自己的代码了,执行ls所对应的代码 ,这个现象就叫做程序替换 程序替换就是让一个进程去执行另一个在磁盘中的程序,让一个进程把一个新的程序运行起来 3. 程序替换的基本原理 当前的进程执行当前代码时,如果执行了函数execl等接口,就会根据你所传入的程序的路径以及你要执行的名称及选项,把磁盘当中的一个其他的程序加载到对应的内存, 用新程序的代码替换当前进程的代码段,用当前进程的数据替换老进程的数据段 站在进程的角度 进程的程序替换有没有创建新的进程呢? 没有,只是将新的程序加载到当前进程的代码段和数据段,用CPU去调度当前进程就可以跑起来了 站在程序的角度 程序被加载了内存中,就可以称程序替换的接口(execl) 为加载器 当创建进程的时候,先有进程数据结构,还是先加载代码和数据? 修改test.c文件为以下内容 #include
2 #include
3 #include
4 int main() 5 { 6 execl("/bin/ls", "ls", "-a", "-l", NULL); 7 } 此时运行可执行程序,自己就写了一个ls命令 创建子进程,让子进程调用execl,在调用execl把代码和数据加载到内存 所以当创建进程的时候,先有进程数据结构,再加载代码和数据 程序替换是整体替换,不是局部替换 修改test.c文件内容如下 #include
2 #include
3 #include
4 #include
5 int main() 6 { 7 pid_t id=fork(); 8 if(id==0) 9 { 10 //child 11 printf("我是子进程:%d\n",getpid()); 12 execl("/bin/ls", "ls", "-a", "-l", NULL); 13 } sleep(5); 14 printf("我是父进程:%d\n",getpid()); 15 waitpid(id,NULL,0); 16 } 查看子进程完成替换后会不会影响父进程,如果影响父进程,就不应该打印父进程的这句话了 过了5秒钟,父进程结果打印出来,说明父进程不受子进程影响 程序替换只会影响调用进程,进程具有独立性 父子进程都有自己独立的PCB 地址空间 页表 也会自己的映射关系 虽然代码有可能是跟父进程共享,当子进程进行程序替换的时候,子进程会加载新进程的代码和数据 操作系统会发生写时拷贝,将代码和数据进行区分 ,使子进程形成新的映射关系,从而使子进程不会影响到父进程 execl 返回值 如果出错了,execl返回值为-1 修改test.c文件内容如下 #include
2 #include
3 #include
4 #include
5 int main() 6 { 7 pid_t id=fork(); 8 if(id==0) 9 { 10 //child 11 printf("我是子进程:%d\n",getpid()); 12 int n=execl("/bin/lsss", "lsss", "-a", "-l", NULL);//lsss命令不存在 13 printf("you can see me:%d\n",n); 14 exit(0); 15 } 16 sleep(5); 17 printf("我是父进程:%d\n",getpid()); 18 waitpid(id,NULL,0); 19 } 20 输入的lsss命令不存在,查询报错后的execl的返回值 程序替换只要成功,就会跑去执行新程序,失败了就会继续向后运行 所以execl程序替换成功不会有返回值——>如果替换失败,一定有返回值——>如果失败了,必定返回——>只要有返回值就失败了 说明不用对execl函数的返回值进行判断,只要继续向后运行一定失败 4. 替换函数 1. execl int execl(const char *path, const char *arg, …); l 代表 list 链表 path:代表你想执行谁 (需要带路径) 执行一个程序最基本的原则为:找到它,加载执行它 arg:你想怎么执行它(若想执行ls指令,是只执行ls,还是执行ls- l 、ls -l -a指令 在命令行怎么执行这个命令,就把参数一个一个的传递给execl就可以了 最终以NULL结尾 具体的实现以及返回值问题上面在演示程序替换时已经使用过啦 2. execv int execv(const char *path, char *const argv[]); v代表vector 容器 path:代表你想执行谁 (需要带路径) 把原来需要一个一个传的参数放在argv[]数组中 修改test.c文件内容 1 #include
2 #include
3 #include
4 #include
5 int main() 6 { 7 pid_t id=fork(); 8 if(id==0) 9 { 10 //child 11 printf("我是子进程:%d\n",getpid()); 12 char *const myargv[]={"ls", "-l", "-a",NULL}; 13 execv("/bin/ls",myargv); 14 exit(0); 15 } 16 sleep(5); 17 printf("我是父进程:%d\n",getpid()); 18 waitpid(id,NULL,0); 19 } 20 执行可执行程序,依旧可以执行ls指令 3. execlp int execlp(const char *file, const char *arg, …); 带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找 file: 不需要传路径,只需要把在PATH环境变量的指令传过来 最后以NULL结尾 #include
2 #include
3 #include
4 #include
5 int main() 6 { 7 pid_t id=fork(); 8 if(id==0) 9 { 10 //child 11 printf("我是子进程:%d\n",getpid()); 12 execlp("ls", "ls", "-l", "-a",NULL); 13 exit(0); 14 } 15 sleep(5); 16 printf("我是父进程:%d\n",getpid()); 17 waitpid(id,NULL,0); 18 } 执行可执行程序,依旧可以执行ls指令 4. execvp int execvp(const char *file, char *const argv[]); 带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找 v代表vector 容器 #include
#include
#include
#include
int main() { pid_t id=fork(); if(id==0) { //child printf("我是子进程:%d\n",getpid()); char* const myargv[]={"ls", "-l", "-a",NULL}; execvp("ls", myargv); exit(0); } sleep(5); printf("我是父进程:%d\n",getpid()); waitpid(id,NULL,0); } 5. execle int execle(const char *path, const char *arg, …, char * const envp[]); path:代表你想执行谁 (需要带路径) envp[]:代表自定义环境变量 如果调用程序替换时,若不想让子进程使用父进程的环境列表,想自定义环境变量,就可以自己传一个环境变量 在另一个目录中创建other.cc (以cc为结尾说明是一个c++程序),并输入以下内容 #include
#include
#include
using namespace std; int main() { for(int i = 0; i < 5; i++) { cout<< "我是另一个程序,我的pid是:"<< getpid()<
#include
#include
#include
int main() { pid_t id=fork(); if(id==0) { //child printf("我是子进程:%d\n",getpid()); W> char*const myenv[]={"MYENV=YouCanSeeMe", NULL}; execle("/home/mydir/my/mm/myother", "myother", NULL,myenv); exit(0); } sleep(1); printf("我是父进程:%d\n",getpid()); int status=0; waitpid(id,&status,0); return 0; } 第一个路径为other.cc生成的可执行程序 myother 所在的 绝对路径 2. 自定义shell 编写极简版本的shell(bash) 目标:为了深刻的理解shell的运行原理 输入 ps ajx |grep bash ,发现bash就是一个进程 由于shell是一个进程,所以用while死循环 缓冲区问题 正常来说,运行可执行程序会显示命令行,但是由于没有\n刷新缓冲区,也没有使用相关的刷新库函数,所以命令行会一直在缓冲区中 直到 程序结束才显示,但是这是个死循环,所以什么都不会显示 执行可执行程序后即可显示命令行 fgets 使用出现空格问题 fgets 标准输入 按行获取 char *fgets(char *s, int size, FILE *stream); 从特定的标准输入当中获取对应的命令行输入,把对应的数据放在缓冲区中 执行可执行程序后,发现在命令行中输入 ls -a ,就会打印出 ls -a,但是输入时会多出一个空行 正常来说,都会使用回车来到下一行,而这个回车被fgets读取到了 将最后的回车符替换成’\0’ 此时就没有空格出现了 完整代码 : mybash.c ? ? ?? buffers #include
#include
#include
#include
#include
#include
#include
#define MAX 1024 #define ARGC 64 #define SEP " " int split (char*commandstr,char*argv[]) { assert(commandstr); assert(argv); argv[0]=strtok(commandstr,SEP);//在commandstr以空格作为分割符 if(argv[0]==NULL)//切割失败 { return -1; } int i=1; while(1) { argv[i]=strtok(NULL,SEP);//继续切割空格 if(argv[i]==NULL) { break; } i++; } W>} void print(char*argv[]) { int i=0; for(i=0;argv[i];i++) { printf("%d:%s\n",i,argv[i]); } } int main() { while(1) { char commandstr[MAX]={0}; char*argv[ARGC]={NULL}; printf("[yzq@mymachine currpath]# "); fflush(stdout); char*s= fgets(commandstr,sizeof(commandstr),stdin); assert(s); (void)s;//保证在release方式发布的时候,因为去掉assert了,所以s就没有被使用,而带来的编译告警, 什么都没做,但是充当一次使用 commandstr[strlen(commandstr)-1]='\0';//将最后的回车符用'\0'覆盖掉 int n= split(commandstr,argv); //从命令行中获取的字符串传入argv中 if(n!=0) continue;//切割失败就什么都不做 // print(argv);//打印字符串 pid_t id=fork(); assert(id>=0); (void)id; if(id==0) { //child execvp(argv[0],argv); exit(1); } int status=0; waitpid(id,&status,0); } } 动图演示
上一篇
DELL服务器RAID配置详细教程
下一篇
直播卖货服务器租用怎么看
相关文章
阿里云国际站服务器:阿里大于的怎么做好短信营销
【Linux】操作系统&&进程概念
欧拉服务器指定静态IP openeuler固定ip地址
在Windows server 2019上开启IIS服务
高并发服务器 poll模型 非阻塞 代码已跑
Nextcloud 使用教程, 十分钟让自己电脑成为私有云盘
服务器流量盈利是怎么回事
nginx参数keepalive_timeout
Android平板浏览器远程Ubuntu服务器使用code-server编程写代码
香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价
7*24H在线售后
高可用资源,安全稳定
1v1专属客服对接
无忧退款试用保障
德讯电讯股份有限公司
电话:00886-982-263-666
台湾总部:台北市中山区建国北路一段29号3楼
香港分公司:九龙弥敦道625号雅兰商业二期906室
服务器租用
香港服务器
日本服务器
台湾服务器
美国服务器
高防服务器购买
香港高防服务器出租
台湾高防服务器租赁
美国高防服务器DDos
云服务器
香港云服务器
台湾云服务器
美国云服务器
日本云服务器
行业新闻
香港服务器租用
服务器资讯
香港云服务器
台湾服务器租用
zblog博客
香港VPS
关于我们
机房介绍
联系我们
Copyright © 1997-2024 www.hkstack.com All rights reserved.