linux下的进程程序替换

进程程序替换

替换概念

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的代码部分开始运行。调用exec并不创建新的进程,所以调用exec前后该进程的id并未改变。

大概意思就是程序替换只是把程序换了,仅仅是从1号程序换到了2号程序,修改了页表的映射地址,但是并没有创建新的PCB,因此没有创建新的进程。

这就是进程替换的概念!

替换函数

在linux手册里,有6个相似的函数,他们虽然参数列表不一样,但是功能一样。

  • 如果这些函数调用成功则加载新的程序,从启动代码开始执行,不再返回。
  • 如果出错则返回-1。
  • 所以exec函数只有出错的返回值而没有成功的返回值。

execl()

l:列表的形式传入参数

int extcl(const char * path, const char* argv,...);

参数:

path:是要打开可执行程序的路径

argv,... :这个语法表示可变的参数列表,可以传入多个不定个数的参数,最后一个参数传入NULL,表示参数传递完成。

描述不清楚,看个例子就明白了:

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>

  5 int main()
  6 {
  7   printf("当前进程开始!\n");
  8   //execl("/usr/bin/ls","ls","--color=auto","-l",NULL);
  9   //一旦调用成功,后续代码都不会执行了!!!                                                                                                                            
 10   execl("/usr/bin/ls","ls","--color=auto","-l", "-i",NULL);
 11   //execl("/usr/bin/top", "top", NULL);
 12   printf("当前进程结束!\n");                                                                                                                                   
 13   return 0;                                                                                                                                                     
 14 }      

因为Linux系统下一切皆文件,ls命令其实就是一个可执行程序,我们使用execl函数,执行这个程序。我们可以改变可变参数列表来使用ls命令不同的功能。

execv()

v:数组的形式传入参数

int extcv(const char * path, char *const argv[]);

参数:

path:仍然是文件路径。

char *argv[]:指针数组,以数组的形式传入。

为了更加适应实际的应用场景,我们使用父进程fork子进程,然后使用子进程进行进程替换,这样不会影响父进程的执行。

如下:

cpp 复制代码
7 #define NUM 32
  8 int main()
  9 {
 10   pid_t id = fork();
 11 
 12   if(id == 0)
 13   {
 14     //子进程
 15     // ls -a -l
 16     printf("子进程开始执行,pid = %d \n",getpid());
 17     //传入指针数组
 18     char *const _argv[NUM] = {
 19      (char*)"ls",
 20      (char*)"-l",
 21       (char*)"-i",
 22       NULL
 23     };
 24     execv("/usr/bin/ls",_argv);  //传入指针数组!!!
 25     exit(1);
 26   }
 27   else{
 28     //父进程
 29     printf("父进程开始等待,pid =%d \n", getpid());                                                                                                                     
 30     int status = 0;
 31     pid_t ret = waitpid(-1, &status, 0); //阻塞等待
 32     if(ret>0)
 33     {
 34       printf("等待成功,退出码为:%d \n", WEXITSTATUS(status));
 35     }
 36   }
 37   return 0;
 38 }

可以看到,子进程帮助父进程完成了执行ls命令,并且没有影响父进程的执行。

execvp()/execlp()

p:表明第一个参数不再是文件路径,而是通过环境变量就可以找到的程序。

看下面的例子更能清楚的解释:

execvp()的例子:

cpp 复制代码
  7 #define NUM 32
  8 int main()
  9 {
 10   pid_t id = fork();
 11 
 12   if(id == 0)
 13   {
 14     //子进程
 15     // ls -a -l
 16     printf("子进程开始执行,pid = %d \n",getpid());
 17     //传入指针数组
 18     char *const _argv[NUM] = {
 19      (char*)"ls",  
 20      (char*)"-l",  
 21       (char*)"-i",  
 22       NULL  
 23     };  
 24     //execv("/usr/bin/ls",_argv);  
 25     execvp("ls",_argv);   //因为环境变量的存在,我们可以只输入ls便可找到该文件。                                                                                        
 26     exit(1);                                             
 27   }                                                                                                                              
 28   else{                                                                                                                          
 29     //父进程                                                                                                                     
 30     printf("父进程开始等待,pid =%d \n", getpid());                                                                              
 31     int status = 0;                                                                                                              
 32     pid_t ret = waitpid(-1, &status, 0); //阻塞等待                                                                              
 33     if(ret>0)                                                                                                                    
 34     {                                                                                                                            
 35       printf("等待成功,退出码为:%d \n", WEXITSTATUS(status));                                                                   
 36     }                                                                                                                            
 37   }                                                                                                                              
 38   return 0;
 39 }

execlp()例子:

仅仅将上面的代码,25行换成26行的内容即可!

cpp 复制代码
   25     //execvp("ls",_argv);   //因为环境变量的存在,我们可以只输入ls便可找到该文件。                                                                   
   26     execlp("ls", "ls", "-l", "-i", NULL);        

execle()/execvpe()

e:可以维护自己的环境变量,将环境变量传给要替换的进程。

以execle为例:

将上面的子进程调用部分修改:

cpp 复制代码
    7 #define NUM 32
    8 int main()
    9 {
   10 
   11   //设置一个环境变量,为的是 让子进程拿到
   12   //因为环境变量具有全局属性
   13   char *const _env[NUM]={
   14     (char*)"xty=123456789",
   15     NULL
   16   };

   31     execle("./myexe", "mycmd", "-a", NULL, _env);   //修改成这样,//其中列表参数是随便传的,myexe是调用的可执行程序。
cpp 复制代码
myexe:
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 int main()
  5 {
  6                                                                                                                                                                         
  7   printf("得到的环境变量xty:%s\n", getenv("xty"));
  8   return 0;
  9 }

可知myexe获取到了环境变量。

如何在C/C++程序里面执行别的语言写的程序。

bash 复制代码
//使用这个命令即可运行
python test.py

首先写一个python文件脚本。待会我们就是用c程序执行它。

使用execlp()调用比较合适。

c 复制代码
  1 #include <stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6 int main()
  7 {
  8   pid_t id = fork();
  9   if(id == 0)
 10   {
 11     //子进程,调用别的语言写的程序
 12     execlp("python", "python", "test.py", NULL);
 13     exit(-1);
 14   }
 15   else{
 16     //父进程
 17     int status = 0;
 18     printf("父进程开始等待: \n");
 19     int ret = waitpid(-1, &status, 0); //阻塞等待
 20     if(ret > 0)
 21     {
 22       printf("父进程等待成功,子进程退出码为:%d \n",WEXITSTATUS(status));
 23 
 24     }
 25   }                                                                                                                                                                     
 26   return 0;
 27 }

我们可以看出python脚本被我们成功调用!

小tips

我们在运行py脚本时,需要运行python这个程序。因为python是一个解释器,我们需要使用解释器来解释test.py文件。

bash 复制代码
python test.py

如果我们给该test.py文件加上执行(x)权限,那么我们这样即可运行该文件:

因此将上面的execlp调用参数,修改为下面这样也可以:

c 复制代码
 //12     execlp("python", "python", "test.py", NULL);
 12     execlp("./test.py", "test.py", NULL);

上面就是程序替换的相关知识,更深入的内容还请读者自行查阅和学习。

相关推荐
苹果醋333 分钟前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
二十雨辰1 小时前
[linux]docker基础
linux·运维·docker
Jason-河山1 小时前
【自动化更新,让商品信息跳舞】——利用API返回值的幽默编程之旅
运维·自动化
饮浊酒1 小时前
Linux操作系统 ------(3.文本编译器Vim)
linux·vim
lihuhelihu2 小时前
第3章 CentOS系统管理
linux·运维·服务器·计算机网络·ubuntu·centos·云计算
哲讯智能科技2 小时前
SAP Business One市场价格解析
运维·sap·erp
矛取矛求2 小时前
Linux系统性能调优技巧
linux
山东布谷科技官方2 小时前
布谷直播源码部署服务器关于数据库配置的详细说明
运维·服务器·数据库·直播系统源码·直播源码·直播系统搭建·直播软件开发
One_Blanks2 小时前
渗透测试-Linux基础(1)
linux·运维·安全
Perishell2 小时前
无人机避障——大疆与Airsim中的角速度信息订阅获取
linux·动态规划·无人机