当前位置: 首页 > news >正文

Linux操作系统学习(进程替换)

文章目录

  • 进程替换
    • 进程替换是什么?
    • 替换的方法
    • 进程替换
  • 简易shell模拟

进程替换

进程替换是什么?

如下图所示:

进程替换就是,把进程B的代码和数据,替换正在执行的进程A的代码和数据在内存中的位置(若代码数据过多可能会改变页表),但进程A的整体部分不发生任何改变(task_struct、A进程地址空间等等)

其实就是用A进程的壳子执行B进程程序,不改变A进程的任何东西,只改变页表物理地址部分和内存中的数据和代码,不创建任何新的进程,并且子进程也不会退出。

替换的方法

一般用到以下六种函数

#include <unistd.h>
int exec l(const char *path, const char *arg, …);
int exec lp(const char *file, const char *arg, …);
int exec le(const char *path, const char *arg, …,char *const envp[]);
int exec v(const char *path, char *const argv[]);
int exec vp(const char *file, char *const argv[]);
int exec ve(const char *path, char *const argv[], char *const envp[]);

命名后缀:

  • l(list) : 表示参数采用列表

  • v(vector) : 参数用数组

  • p(path) : 有p自动搜索环境变量PATH

  • e(env) : 表示自己维护环境变量

    程序运行时的环境变量信息(函数不会给你自动继承父进程的环境变量,需要手动设置)

返回值:

若替换失败则返回-1,但其实可以不用检查返回值因为:

  • 调用成功一定执行替换的程序

  • 调用失败一定执行原本的程序

  • int execl(const char *path, const char *arg, …);

void test1()    
{    
pid_t id = fork();    
if(id == 0)    
{    
printf("你好\n");    /*********************************************开始替换******************************************/execl("/usr/bin/ls","ls","-a","-l","-i",NULL);   //你要执行谁,想怎么执行(在命令行怎么执行就怎么执行),可变参数列表以NULL结尾//或者想要执行自己的程序 execl("./当前路径或者 /.../...绝对路径","可执行程序名",NULL);/*********************************************替换完成/失败******************************************/printf("hello\n");    }    sleep(1);    
printf("child exchange succeed\n");     
}    

  • int execlp(const char *file, const char *arg, …);
void test2()
{pid_t id = fork();if(id == 0){char* argv[] = {"ls","-a","-i","-l",NULL};//就是把可变参数列表以数组的形式传给execvprintf("exchange test2--->:\n");
/*********************************************开始替换******************************************/execv("/usr/bin/ls",argv);
/*********************************************替换完成/失败******************************************/printf("exchange fail\n");}sleep(1);printf("exchange succeed\n");
}

  • int execle(const char *path, const char *arg, …,char *const envp[]);
void test3()
{pid_t id = fork();if(id == 0){printf("exchange test3---->\n");
/*********************************************开始替换******************************************/execlp("ls","ls","-l","-a","-i",NULL);// 第一个你要执行的是谁但不用带路径,path会根据这个程序名去自动搜索它在什么位置,第二个是要怎么执行
/*********************************************替换完成/失败******************************************/printf("exchange fail\n");}sleep(1);printf("exchange succeed\n");}

  • int execvp(const char *file, char *const argv[]);
void test4()
{pid_t id = fork();if(id == 0){printf("exchange test4---->\n");char* argv[] = {"ls","-a","-l","-i",NULL};
/*********************************************开始替换******************************************/execvp("ls",argv); //第一个参数告诉path要执行的程序他会自动去找路径,第二个参数从可变参数列表变为自定义数组
/*********************************************替换完成/失败******************************************/printf("exchange fail\n");}sleep(1);printf("exchange succeed\n");
}

  • int execle(const char *path, const char *arg, …,char *const envp[]);
void test5()
{pid_t id = fork();if(id == 0){printf("exchange test5---->\n");
/*********************************************开始替换******************************************/char* env[] = {"my_env=hello",NULL};execle("./print","print",NULL,env);//最后一个参数env指定了新程序的环境列表。参数env对应于新程序的environ数组//传递自己的环境变量给print
/*********************************************替换完成/失败******************************************/printf("exchange fail\n");}sleep(1);printf("exchange succeed\n");}int main()
{extern char** environ;for(int i = 0;environ[i];i++){if(environ[i] == "PATH")continue;//path显示的太多,这里屏蔽掉printf("%s\n",environ[i]);}return 0;
}

  • int execve(const char *path, char *const argv[], char *const envp[]);
void test6()
{pid_t id = fork();if(id == 0){printf("exchange test5---->\n");
/*********************************************开始替换******************************************/char* argv[] = {"print",NULL};char* env[] = {"my_env=hello",NULL};execve("./print",argv,env);
/*********************************************替换完成/失败******************************************/printf("exchange fail\n");}sleep(1);printf("exchange succeed\n");}int main()
{extern char** environ;for(int i = 0;environ[i];i++){if(environ[i] == "PATH")continue;printf("%s\n",environ[i]);}return 0;
}

可以看出所有的函数都是在execve基础上封装的


进程替换

  • 子进程需要替父进程执行一些任务就需要进程替换

  • 进程替换只替换子进程在内存中的代码和数据,以及页表物理地址部分

  • 进程替换不会创建新进程,不会退出子进程

  • 虽然父子代码是共享的,但是进程替换会更改内存的代码和数据,所以要发生写实拷贝

  • fork创建子进程后,在代码中exec…只会替换子进程,因为进程具有独立性

程序替换的本质是把程序的代码数据加载到指定进程的上下文中


简易shell模拟

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>void myshell()
{char command[128];char* argv[64];while(1){command[0] = 0;printf("[awd@VM-16-4-centos myshell]----->");	//打印前缀	fflush(stdout);									//刷新缓冲区fgets(command,128,stdin);						//输入命令command[strlen(command) - 1] = 0;				//先当作整个字符串存入command,-1是除去\n//fflush(stdout);									//printf("%s\n",command);验证const  char* set = " ";							//设置分隔符argv[0] = strtok(command,set);					//把字符串拆解成指令int i = 1;								while( argv[i] = strtok(NULL,set) )				//类似strcpy,赋值到NULL退出i++;/*for(int j = 0;j < i;j++)printf("%s\n",argv[j]);验证*/if(strcmp(argv[0],"cd") == 0)					//在子进程cd影响的只是子进程,所以要再父进程处理{if(argv[1])chdir(argv[1]);continue;}if(fork() == 0)								 //创建子进程{execvp(argv[0],argv);						 //替父进程执行这些指令exit(1);								     	 //若执行到这说明替换失败,设置退出码为1}waitpid(-1,NULL,0);								//等待任意一个子进程结束int status = 0;if(strcmp(argv[0],"echo") == 0 && strcmp(argv[1],"$?") == 0)	//打印退出码和终止信号printf("exit code:%d ,exit signal:%d \n",WEXITSTATUS(status),WTERMSIG(status));}}int main()
{myshell();return 0;
}

通过这个简易shell来把之前学到的总结一下

  • 一般让子进程替父进程执行一些第三方命令,那么就需要用到 进程替换和fork
  • 子进程每次执行结束需要进程等待,为了结束他的僵尸进程并获取它的退出信息(退出码、终止信号
  • 每次进程退出后又会重新创建子进程,所以echo $? 查看的是最近一次执行的退出码
  • 证明了每一次命令行执行的指令都是一次进程,是基于bash为父进程创建的子进程

上面这个简陋shell综合了 :fork、进程替换函数、进程等待函数、进程退出函数、退出码/终止信号,加深了这些接口的理解

相关文章:

Linux操作系统学习(进程替换)

文章目录进程替换进程替换是什么&#xff1f;替换的方法进程替换简易shell模拟进程替换 进程替换是什么&#xff1f; 如下图所示&#xff1a; ​ 进程替换就是&#xff0c;把进程B的代码和数据&#xff0c;替换正在执行的进程A的代码和数据在内存中的位置&#xff08;若代码…...

【C++从入门到放弃】类和对象(中)———类的六大默认成员函数

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《C从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 类和对…...

白盒测试重点复习内容

白盒测试白盒测试之逻辑覆盖法逻辑覆盖用例设计方法1.语句覆盖2.判定覆盖(分支覆盖)3.条件覆盖4.判定条件覆盖5.条件组合覆盖6.路径覆盖白盒测试之基本路径测试法基本路径测试方法的步骤1.根据程序流程图画控制流图2.计算圈复杂度3.导出测试用例4.准备测试用例5.例题白盒测试总…...

【13】linux命令每日分享——groupadd建立组

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…...

《第一行代码》 第十章:服务

一&#xff0c;在子线程中更新UI 1&#xff0c;新建项目&#xff0c;修改布局代码 <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"&g…...

简单介绍编程进制

十进制 十进制的位权为 10&#xff0c;比如十进制的 123&#xff0c;123 1 * 10 ^ 2 2 * 10 ^ 1 3 * 10 ^ 0。 二进制 二进制的位权为 2&#xff0c;比如十进制的 4&#xff0c;二进制为 100&#xff0c;4 1 * 2 ^ 2 0 * 2 ^ 1 0 *2 ^ 0。 Java7 之前&#xff0c;不支…...

windows忘记开机密码怎么办

windows忘记开机密码怎么办 清除windows登录密码 清除windows登录密码简单方法 开机到欢迎界面时&#xff0c;按CtrlAltDelete两次&#xff0c;跳出帐号窗口&#xff0c;输入用户名&#xff1a;administrator&#xff0c;回车&#xff0c; 或者启动时按F8 选“带命令行的安全…...

SpringCloud:Eureka

目录 一、eureka的作用 二、搭建Eureka服务端 三、添加客户端 四、服务发现 提供者与消费者 服务提供者&#xff1a;一次业务中&#xff0c;被其它微服务调用的服务。&#xff08;提供接口给其它微服务) 服务消费者&#xff1a;一次业务中&#xff0c;调用其它微服务的服…...

如何获取或设置CANoe以太网网卡信息(SET篇)

CAPL提供了一系列函数用来操作CANoe网卡。但是,但是,首先需要明确一点,不管是获取网卡信息,还是设置网卡信息,只能访问CAPL程序所在的节点下的网卡,而不是节点所在的以太网通道下的所有网卡 关于第一张图中,Class节点下,有三个网卡:Ethernet1、VLAN 1.100、VLAN 1.200…...

【软件测试面试题】项目经验?资深测试 (分析+回答) 我不信你还拿不到offer......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 在面试过程中&#…...

tensorflow lite简介-移动设备端机器学习

TensorFlow Lite 是一组工具&#xff0c;可帮助开发者在移动设备、嵌入式设备和 loT 设备上运行模型&#xff0c;以便实现设备端机器学习。 支持多平台 支持多种平台&#xff0c;涵盖 Android 和 iOS 设备、嵌入式 Linux 和微控制器。 原理/流程 工作原理或者使用流程就是上面…...

Node.js常用知识

1、什么是 Node.js 【】Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。浏览器是 js 的前端运行环境&#xff0c;node.js 是 js 的后端运行环境。他们都有 V8 引擎&#xff0c;有各自的内置 API 2、fs 文件系统模块 【】fs 模块是 Node.js 官方提供的、用来操作文件…...

踩坑:maven打包失败的解决方式总结

Maven打包失败原因总结如下&#xff1a; 失败原因1&#xff1a;无法使用spring-boot-maven-plugin插件 使用spring-boot-maven-plugin插件可以创建一个可执行的JAR应用程序&#xff0c;前提是应用程序的parent为spring-boot-starter-parent。 需要添加parent的包spring-boot…...

【C++】位图

文章目录位图概念位图操作位图代码位图应用位图概念 boss直接登场&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中❓ 40亿个整数&#xff0c;大概就是16GB。40亿个字节大概就是4GB。 1Byt…...

蓝桥杯-考勤刷卡

蓝桥杯-考勤刷卡1、问题描述2、解题思路3、代码实现1、问题描述 小蓝负责一个公司的考勤系统, 他每天都需要根据员工刷卡的情况来确定 每个员工是否到岗。 当员工刷卡时, 会在后台留下一条记录, 包括刷卡的时间和员工编号, 只 要在一天中员工刷过一次卡, 就认为他到岗了。 现在…...

如何利用站内推广和站外推广提高转化率?

在如今的网络时代&#xff0c;拥有一个好的网站是非常重要的。但是&#xff0c;光有一个好的网站是不够的&#xff0c;为了达到我们的目标&#xff0c;需要不断地提高网站的转化率。而在实现这个目标的过程中&#xff0c;站内推广和站外推广是两个非常关键的因素。 站内推广是…...

Java多线程(三)——线程池及定时器

线程池就是一个可以复用线程的技术。前面三种多线程方法就是在用户发起一个线程请求就创建一个新线程来处理&#xff0c;下次新任务来了又要创建新线程&#xff0c;而创建新线程的开销是很大的&#xff0c;这样会严重影响系统的性能。线程池就相当于预先创建好几个线程&#xf…...

Linux命令行安装Oracle19c教程和踩坑经验

安装 下载 从 Oracle官方下载地址 需要的版本&#xff0c;本次安装是在Linux上使用yum安装&#xff0c;因此下载的是RPM。另外&#xff0c;需要说明的是&#xff0c;Oracle加了锁的下载需要登录用户才能安装&#xff0c;而用户是可以免费注册的&#xff0c;这里不做过多说明。 …...

Linux常用命令等

目录 1.Linux常用命令 (1)系统命令 (2)文件操作命令 2.vim编辑器 3.linux系统中,软件安装 (1) rpm 安装,RedHat Package Manager (2)yum 安装 (3)源代码编译安装 1.Linux常用命令 Linux命令是非常多的,对于像嵌入式开发工程师,运维工程师需要掌握的命令是非常多的.对于…...

CEC2014:鱼鹰优化算法(Osprey optimization algorithm,OOA)求解CEC2014(提供MATLAB代码

一、鱼鹰优化算法简介 鱼鹰优化算法&#xff08;Osprey optimization algorithm&#xff0c;OOA&#xff09;由Mohammad Dehghani 和 Pavel Trojovsk于2023年提出&#xff0c;其模拟鱼鹰的捕食行为。 鱼鹰是鹰形目、鹗科、鹗属的仅有的一种中型猛禽。雌雄相似。体长51-64厘米…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理&#xff1a;检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;RankRAG&#xff1a;Unifying Context Ranking…...