Linux之进程替换
进程替换
- 1.什么是进程替换
- 2.替换函数
- 2.1 execl函数
- 2.2 execv函数
- 2.3 execlp函数
- 2.4 execvp函数
- 2.5 在自己的C程序上如何运行其他语言的程序?
- 2.6 execle 函数
- 2.7 小结
- 3.一个简易的shell
1.什么是进程替换
fork()之后,父子各自执行父进程代码的一部分,父子代码共享,数据写时拷贝各自一份,如果子进程想就执行一个全新的进程呢?
进程的程序替换,来完成这个功能。
程序替换:是通过特定的接口,加载磁盘上的一个权限的程序(代码和数据),加载到进程的地址空间中。

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exex函数以执行另外的一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新进程替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec函数前后进程的id并未改变。
所以,进程替换,并没有创建新的子进程,所谓的exec*函数,本质就是加载程序的函数。
2.替换函数
*exec 函数:**功能其实就是加载器的底层接口
2.1 execl函数

1 #include <stdio.h>2 #include <unistd.h>3 4 5 int main()6 {7 printf("当前进程的开始代码!\n");8 9 // execl("/usr/bin/ls","ls",NULL);10 // execl("/usr/bin/ls","ls","-l",NULL);11 execl("/usr/bin/ls","ls","-l","--color=auto","-a",NULL); 12 printf("当前进程的结束代码!\n"); 13 14 return 0; 15 }
运行结果:
[jyf@VM-12-14-centos 进程]$ ./mytest11
当前进程的开始代码!
. Makefile myproc.c mytest10 mytest2 mytest4
可见,并没有执行printf(“当前进程的结束代码!\n”);这条语句,进程发生了替换。
execl是程序替换,调用该函数成功之后,会将当前进程的所有代码和数据都进行替换!包括已经执行的和没有执行的!所以一旦调用成功,后续的所有代码都不会执行。
进程替换应用实例
1 #include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 #include <sys/wait.h>5 6 int main()7 {8 //为什么我要创建子进程?9 //如果不创建,我们替换的进程就是父进程,如果创建了,我们替换的进程就是子进程,而不影响父进程。10 //因为我们想让父进程聚焦在读取数据,解析数据,指派进程执行代码的功能! 11 12 //1.显示一个提示符:root@localhost# 13 //2.获取用户输入的字符串,fgets,scanf,-> ls -a -l14 //3.对字符串进行解析15 while(1) 16 { 17 pid_t id = fork();18 if(id == 0) 19 { 20 //子进程 21 printf("子进程开始运行,pid:%d\n",getpid());22 sleep(3); 23 execl("/usr/bin/ls","ls","-a","-l",NULL);24 exit(1); 25 } 26 else{ 27 ;//父进程 28 printf("父进程开始运行:%d\n",getpid()); 29 int status = 0; 30 pid_t id = waitpid(-1,&status,0);//阻塞等待,一定是子进程先运行完毕,然后父进程获取之后,才退出!31 if(id>0) 32 { 33 printf("wait success,exit code:%d\n",WEXITSTATUS(status));34 } 35 } 36 } 37 return 0;38 }
加载新程序之前,父子进程的代码和数据的关系?代码共享,数据写时拷贝。
当子进程加载新程序的时候,不就是一种写入吗?代码要不要写时拷贝呢?将父子进程的代码分离?必须分离。
int execl(const char* path,const char* arg,…); 父子进程在代码和数据上就彻底分开了,虽然曾经并不冲突。
2.2 execv函数

代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h> int main()
{ pid_t id = fork(); if(id == 0) { printf("子进程开始运行:%d\n",getpid()); char* const _argv[] = {(char*)"ls",(char*)"-a",(char*)"-l",NULL}; execv("/usr/bin/ls",_argv); exit(1); } else { printf("父进程开始运行:%d\n",getpid()); int status =0; pid_t id = waitpid(-1,&status,0); if(id>0) { printf("wait success,exit code:%d\n",WEXITSTATUS(status)); } } return 0;
}
运行结果:
[jyf@VM-12-14-centos lesson3-28]$ ./mytest
父进程开始运行:26522
子进程开始运行:26523
total 36
drwxrwxr-x 2 jyf jyf 4096 Mar 28 22:45 .
drwx------ 19 jyf jyf 4096 Mar 28 17:26 ..
-rwxrwxr-x 1 jyf jyf 8616 Mar 28 22:45 mytest
-rwxrwxr-x 1 jyf jyf 8616 Mar 28 21:57 mytest1
-rw-rw-r-- 1 jyf jyf 532 Mar 28 22:45 test1.c
wait success,exit code:0
2.3 execlp函数

要执行程序,必须先找到程序!带路径,不带路径都能找到吗?只要在环境变量中存在即可。
我会自己在环境变量PATH中进行查找,你不用告诉我你要执行的程序在哪里!!
2.4 execvp函数
// int execvp(const char *file, char *const argv[]);
execvp("ls",_argv);
const char* file:具体要执行的程序,它会到环境变量里面去找
具体实施方法如execv函数。
2.5 在自己的C程序上如何运行其他语言的程序?
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> const char* myfile = "/home/jyf/lesson3-28/mycmd"; int main() { pid_t id = fork(); if(id == 0) { printf("子进程开始运行:%d\n",getpid());
W> char* const _argv[] = {(char*)"ls",(char*)"-a",(char*)"-l",NULL}; // execv("/usr/bin/ls",_argv); //execlp("ls","ls","-a","-l",NULL); //execvp("ls",_argv); //execl(myfile,"mycmd","-a",NULL); //execlp("python","python","test.py",NULL); //运行python程序 //execl("/usr/bin/python","python","test.py",NULL); //运行python程序execlp("bash","bash","test.sh",NULL); //运行shell程序 exit(1); } else { printf("父进程开始运行:%d\n",getpid()); int status =0; pid_t id = waitpid(-1,&status,0); if(id>0) { printf("wait success,exit code:%d\n",WEXITSTATUS(status)); } } return 0; }
2.6 execle 函数
int execle(const char *path, const char *arg, ..., char * const envp[]);
char* const envp[ ]:将环境变量传递给要替换的程序
2.7 小结

命名理解:这些函数看起来很容易混,但只要掌握规律就很好记。
l(list):表示参数要自己给具体路径
v(vector):表示可变参数都放到数组中
p(path):有p自动在环境变量中搜索PATH
e(env):表示自己创建维护环境变量,将环境变量传递给要替换的进程
为什么要替换?
一定和应用场景有关,我们有时候必须让子进程执行新的程序
3.一个简易的shell
#include <stdio.h> #include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>#include <string.h>#define NUM 1024#define SIZE 32#define SEP " "//保存完整的命令行字符串char cmd_line[NUM];//保存打散之后的命令行字符串char* g_argv[SIZE];//shell 运行原理:父进程读取命令,解析命令,派发给子进程命令,让子进程去执行命令int main(){//0.命令行解释器,一定是一个常驻内存的进程,不退出while(1){//1.打印出提示信息,[root@localhost myshell]#printf("[root@localhost myshell]# ");fflush(stdout);memset(cmd_line,'\0',sizeof(cmd_line));//2.获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]if(fgets(cmd_line,sizeof(cmd_line),stdin) == NULL){continue;}cmd_line[strlen(cmd_line)-1] = '\0';//将回车键'\n',替换成'\0'//"ls -a -l -i\n\0"// printf("echo %s\n",cmd_line);g_argv[0] = strtok(cmd_line,SEP);//将输入的字符串按空格进行分割,第一次调用,要传入原始字符串int index = 1;if(strcmp(g_argv[0],"ls") == 0) //ls自带调色实现{
W> g_argv[index++] = "--color=auto";}if(strcmp(g_argv[0],"ll") == 0) //ll命令的简写的实现{
W> g_argv[0] = "ls";
W> g_argv[1] = "-l";
W> g_argv[2] = "--color=auto";index+=2;}
W> while(g_argv[index++] = strtok(NULL,SEP));//第二次调用,如果还要解析原始字符串,传入NULL//for debug//for(index =0;g_argv[index];index++)//{//procrintf("g_argv[%d]: %s\n",index,g_argv[index]);//}//4.TODO,内置命令,让父进程自己执行的命令,我们叫内置命令,内建命令//内建命令本质其实就是shell中的一个函数调用if(strcmp(g_argv[0],"cd") == 0) //not child execute ,father execute{if(g_argv[1]!=NULL){chdir(g_argv[1]); //cd path}continue;}//5.fork()pid_t id = fork();if(id ==0){//procrintf("下面功能让子进程进行的\n");execvp(g_argv[0],g_argv); exit(1);}}//fatherint status = 0;pid_t ret = waitpid(-1,&status,0);if(ret>0){//printf("exit code:%d\n",WEXITSTATUS(status));}}return 0;}
相关文章:
Linux之进程替换
进程替换1.什么是进程替换2.替换函数2.1 execl函数2.2 execv函数2.3 execlp函数2.4 execvp函数2.5 在自己的C程序上如何运行其他语言的程序?2.6 execle 函数2.7 小结3.一个简易的shell1.什么是进程替换 fork()之后,父子各自执行父进程代码的一部分&…...
关于清除浮动
浮动最早是用来做图文排版,为了让块级元素同行显示,而html中块元素是有自己的排列规则,一般独占一行。所以有了浮动元素,一旦元素浮动了就会脱离文档流,产生问题。怎么去清除浮动:(1)…...
Uber H3 index 地图索引思考
H3 是 uber 设计的六边形空间索引,go 语言操作包是 h3-go,可以通过经纬度获取所在的 h3 六边形边界,每个经纬度对应的六边形都是确定的,每个六边形唯一对应了一个 h3index。在业务开发中,我们可以通过 h3index 来对地理…...
多线程的几种状态
Java-多线程的几种状态🔎1.NEW( 系统中线程还未创建,只是有个Thread对象)🔎2.RUNNABLE( (就绪状态. 又可以分成正在工作中和即将开始工作)🔎3.TERMINATED(系统中的线程已经执行完了,Thread对象还在)🔎4.TIMED_WAITING(指定时间等待…...
【算法题】1574. 删除最短的子数组使剩余数组有序
题目: 给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。 一个子数组指的是原数组中连续的一个子序列。 请你返回满足题目要求的最短子数组的长度。 示例 1: …...
理解对数——金融问题中的自然对数(以e为底的对数)
第3章 金融问题(Financial Matters)——金融问题中的自然对数If thou lend moneyto any ofMy people. ...thou shalt not beto him as a creditor;neither shall yelay upon him interest.(如果你借钱给我的任何人。 ……你不应该是他的债权人;也不可向他加息。)——…...
vue2进阶学习之路
HTML、CSS和JavaScript基础 在学习Vue2之前,需要掌握HTML、CSS和JavaScript的基础知识。包括HTML的标签、CSS的布局和样式、JavaScript的变量类型、条件语句、循环语句等。 Vue2的基础知识 掌握Vue2的基本概念和语法,包括Vue2实例、数据绑定、指令、组件…...
决策树ID3算法
1. 决策树ID3算法的信息论基础 机器学习算法其实很古老,作为一个码农经常会不停的敲if, else if, else,其实就已经在用到决策树的思想了。只是你有没有想过,有这么多条件,用哪个条件特征先做if,哪个条件特征后做if比较优呢&#…...
C++模板基础(一)
函数模板(一) ● 使用 template 关键字引入模板: template void fun(T) {…} – 函数模板的声明与定义 – typename 关键字可以替换为 class ,含义相同 – 函数模板中包含了两对参数:函数形参 / 实参;模板形…...
生产者消费者模型线程池(纯代码)
目录 生产者消费者模型 条件变量&&互斥锁(阻塞队列) makefile Task.hpp BlockQueue.hpp BlockQueueTest.cc 信号量&&互斥锁(环形队列) makefile RingQueue.hpp RingQueueTest.cc 线程池(封…...
K8s 应用的网络可观测性: Cilium VS DeepFlow
随着分布式服务架构的流行,特别是微服务等设计理念在现代应用普及开来,应用中的服务变得越来越分散,因此服务之间的通信变得越来越依赖网络,很有必要来谈谈实现微服务可观测性中越来越重要的一环——云原生网络的可观测。K8s 是微服务设计理念能落地的最重要的承载体,本文…...
3.29面试题
文章目录内存内存管理执行过程要点面试题内存 内存管理 由JVM管理 堆:new出来的对象(包括成员变量、数组元素、方法的地址)栈:局部变量(包括方法的参数)方法区:.class字节码文件(…...
操作系统漏洞发现
操作系统漏洞发现前言一、操作系统漏洞发现1.1 namp2. Goby3. Nessus二,进行渗透测试2.1 使用工具进行渗透1. metasploit2.2 EXP2.3 复现文章三,操作系统漏洞修复前言 不管是对于App来说,还是web站点来说,操作系统是必须的&#x…...
Linux gdb调试底层原理
TOC 前言 linux下gdb调试程序操作过程参考本人文章:gdb调试操作; 这里不再叙述; 本文主要内容是介绍GDB本地调试的底层调试原理,我们来看一下GDB是通过什么机制来控制被调试程序的执行顺序; 总结部分是断点调试的底层原理,可以直接跳转过去先看看大概…...
LC-1647. 字符频次唯一的最小删除次数(哈希+计数)
1647. 字符频次唯一的最小删除次数 难度中等56 如果字符串 s 中 不存在 两个不同字符 频次 相同的情况,就称 s 是 优质字符串 。 给你一个字符串 s,返回使 s 成为 优质字符串 需要删除的 最小 字符数。 字符串中字符的 频次 是该字符在字符串中的出现…...
HTTP状态码
100: 接受,正在继续处理 200: 请求成功,并返回数据 201: 请求已创建 202: 请求已接受 203: 请求成为,但未授权 204: 请求成功,没有内容 205: 请求成功,重置内容 206: 请求成功,返回部分内容 301: 永久性重定…...
【Linux】初见“which命令”,“find命令”以及linux执行命令优先级
文章目录1.which命令1.1 whereis命令1.2 locate命令1.3 搜索文件命令总结2.find命令2.1 find之exec用法2.2 管道符之xargs用法3 Linux常用命令4.命令执行优先级1.which命令 查找命令文件存放目录 搜索范围由环境变量PATH决定(echo $PATH) which命令格式࿱…...
update case when 多字段,多条件, mysql中case when用法
文章目录 前言 sql示例 普通写法: update case when写法 update case when 多字段写法 case when语法 case when 的坑 1、不符合case when条件但是字段被更新为null了 解决方法一:添加where条件 解决方法二:添加else 原样输出 2、同一条数据符…...
mysql隐式转换 “undefined“字符串匹配到mysql int类型0值字段
描述:mysql 用字符串搜索 能搜到int类型查询结果 mysql int类型条件用字符串查询 table: CREATE TABLE all_participate_records (id bigint unsigned NOT NULL AUTO_INCREMENT,created_at datetime(3) DEFAULT NULL,updated_at datetime(3) DEFAULT NULL,deleted…...
Redis八股文
1.Redis是什么? Redis 是一个基于 C 语言开发的开源数据库(BSD 许可),与传统数据库不同的是 Redis 的数据是存在内存中的(内存数据库),读写速度非常快,被广泛应用于缓存方向。并且,…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...
拟合问题处理
在机器学习中,核心任务通常围绕模型训练和性能提升展开,但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正: 一、机器学习的核心任务框架 机…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
Copilot for Xcode (iOS的 AI辅助编程)
Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot,它能根据上下文补全代码,快速生成常用…...
Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...
