Linux进程程序替换

1.进程程序替换

1.1为什么要进行进程程序替换

fork()创建子进程后,创建的子进程要么和父进程执行一样的代码,要么执行不同的代码分支(通过fork的返回值控制),但这样还是不够灵活。假如有很多的功能已经用别的程序实现好了,那么就不需要在父进程中控制子进程执行不同的代码分支,让子进程在自己的分支中完成这些功能;而是可以直接拿一个已有的程序替换掉子进程,使子进程的代码完全变成所替换程序的代码。

而且在子进程需要完成较为复杂的功能或是多项功能时,分支就显得力不从心了。所以进程需要调用exec族中的某一个函数来进行程序替换, 让一个进程来执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不会创建新进程,所以调用exec前后被替换进程的id并未改变。

1.2进程替换的原理

在这里插入图片描述
exec 函数不是创建调用进程的子进程,而是创建一个新的进程取代调用进程自身。新进程会用自己的全部地址空间,覆盖调用进程的地址空间,但进程的 PID 保持不变。exec 只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段。

2.替换函数exec函数族

exec函数族的作用: 根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

exec族函数共有六个,功能都是进程程序替换,但多个不同的函数接口使得使用更加灵活。其中exceve()是系统调用接口,其余5个底层都封装了execve()

函数原型如下 :

#include <unistd.h>
int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, ... /*,(char *)0, char *const envp[]*/);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
int execvp(const char *file, char *const argv[]);

返回值 :

  • 这六个函数返回值相同
  • 函数调用失败,返回 -1
  • 当调用成功,即加载新的程序,替换后的进程启动开始执行,exec族函数不再返回
  • 特殊的地方是:函数调用成功,不返回

参数:
函数名都是在exce的基础上,加上l、v、e、p组成新的函数名,加哪个字母都有各自的含义:

  • l / v 必须有一个,也只能有一个, 带 l 参数格式是列表,带 v 参数格式是数组
  • p 有p会自动搜索环境变量PATH,则可以不带路径只要文件名(但文件必须放在PATH环境变量指定路径)。没有p,则必须指定文件路径
  • e 有e则不使用当前环境变量,需要自己设置环境变量;没e,则使用当前环境变量,无需设置环境变量

2.1execv

int execv(const char *path, char *const argv[]);
#include<stdio.h>
#include<unistd.h>
int main() {
    char* arg[] = {"ls","-a","-l","/",NULL };//参数格式:数组
    execv("/bin/ls", arg);
    printf("Hello Linux!\n");
    return 0;
}

进程被 ls 程序替换后,只执行 ls 的代码,并不会再输出 Hello Linux!
在这里插入图片描述

2.2execl

int execl(const char *path, const char *arg0, ... /*, (char *)0 */);

execl()其中后缀 “l” 代表 list 也就是参数列表的意思,第一参数 path 字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]… 最后一个参数须用空指针NULL作结束。

#include <stdio.h>
#include <unistd.h>

int main(){
  execl("/bin/ls","ls","/",NULL);//参数格式:路径,列表
  printf("Hello Linux!\n");
  return 0;
}

在这里插入图片描述

2.3execvp/execlp

p:会自动搜索环境变量PATH,则可以不带路径只要文件名(但文件必须放在PATH环境变量指定路径)

execvp

int execvp(const char *file, char *const argv[]);
#include <stdio.h>
#include <unistd.h>

int main(){
  char* argv[]={"ls","-a","-l",NULL};
  execvp("ls",argv);//无需写全路径
  printf("Hello Linux!\n");
  return 0;
}                                     

在这里插入图片描述
execlp

int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
#include <stdio.h>
#include <unistd.h>

int main(){
  execlp("ls","-a","-l",NULL);   
  printf("Hello Linux!\n");
  return 0;
}

在这里插入图片描述

2.3execve/execle

e:不使用当前环境变量,需要自己设置环境变量

execve

int execve(const char *path, char *const argv[], char *const envp[]);
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
  char* argv[]={"ls","-a","-l",NULL};
  char* envp[]={"PATH=/home/ryx",NULL};
  execve("/bin/ls",argv,envp);          
  return 0;
}

在这里插入图片描述

execle

int execle(const char *path, const char *arg0, ... /*,(char *)0, char *const envp[]*/);
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
  char* envp[]={"PATH=/home/ryx",NULL};
  execle("/bin/env",NULL,envp);     
  return 0;

}

在这里插入图片描述

3.函数与进程的之间的相似性

exec/exit就像call/return

一个C程序有很多函数组成。一个函数可以调用另外一个函数,同时传递给它一些参数。被调用的函数执行一定的操作,然后返回一个值。每个函数都有他的局部变量,不同的函数通过call/return系统进行通信。这种通过参数和返回值在拥有私有数据的函数间通信的模式是结构化程序设计的基础。Linux鼓励将这种应用于程序之内的模式扩展到程序之间。
在这里插入图片描述一个C程序可以fork/exec另一个程序,并传给它一些参数。这个被调用的程序执行一定的操作,然后通过exit(n)来返回值。调用它的进程可以通过wait(&ret)来获取exit的返回值。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值