IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux 进程(二) -> 正文阅读

[系统运维]Linux 进程(二)

前言

fork创建一个子进程的一般目的有哪些呢?
(1)一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络进程中是常见的—父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
(2)一个进程要执行不同的程序。这对shell是最常见的情况,这种情况下,子进程从fork返回后立即调用exec。

上一节我们详细介绍了第一点,接下来我们介绍下第二点。
我们用fork函数创建新进程后,经常在新进程调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有发生改变。

API介绍

一、exec族:execl, execlp, execle, execv, execvp, execvpe

功能:在调用进程内部执行一个可执行文件,可执行文件既是可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
函数原型:
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg,…);
int execle(const char *path, const char *arg,…, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
返回:exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
参数说明:
path:可执行文件的路径名字
arg:可执行程序所带的参数,第一个参数为可执行文件名字(没有带路径),且arg必须以NULL结束
argv[]:可执行文件所带参数指针数组
file:如果参数file中包含/,则就将其视为路径名,否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件

exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
l:使用参数列表
p:使用文件名,并从PATH环境进行寻找可执行文件
v:应先构造一个指向各参数的指针数组,然后该数组的地址作为这些函数的参数
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量。

带有l的exec族函数,包括execl, execlp, execle,要求将新程序的每个命令行参数都说明为一个单独的参数,这种参数表以空指针结尾。注意第一个命令行参数即argv[0]为可执行文件名字。

以execl函数为例子来说明:

#include <unistd.h>
#include <stdio.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main()
{
		printf("before exec!\n");
        if(execl("./pro","pro","hello","world",NULL)==-1)
        {
                printf("exec failed!\n");
				perror("why");
        }
        printf("code end!\n");
        return 0;
}
//文件pro.c
#include <stdio.h>
int main(int argc,char *argv[])
{
        int i=0;
        printf("argc:%d\n",argc);
        printf("argv:\n");
        for(i=0;i<argc;i++)
        {
                printf("%s\n",*argv);
                argv++;
        }
        return 0;
}

如果该路径不存在pro可执行文件,调用失败,会设置errno并返回-1,通过perror函数打印错误原因。同时程序也会往下运行,打印字符串”code end!”。

before exec!
exec failed!
why: No such file or directory
code end!

如果调用成功,程序不会往下运行,不打印字符串”code end!”,直接执行pro,输出命令行参数信息。

before exec!
argc:3
argv:
pro
hello
world

如何将当前路径添加到环境变量?
查看PATH环境变量。

Ubuntu@Embed_Learn:~/learn/process$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

通过pwd指令获取当前路径。

Ubuntu@Embed_Learn:~/learn/process$ pwd
/home/Ubuntu/learn/process

通过添加当前路径到PATH环境变量。

Ubuntu@Embed_Learn:~/learn/process$ export PATH=$PATH:/home/Ubuntu/learn/process

查看当前路径添加到PATH环境变量是否成功。

Ubuntu@Embed_Learn:~/learn/process$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/Ubuntu/learn/process

带有p的exec族函数,包括execlp, execvp, execvpe,如果参数file中包含‘/’,则就将其视为路径名,否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件。

以execlp函数为例子来说明:

#include <unistd.h>
#include <stdio.h>
//函数原型:int execlp(const char *file, const char *arg, ...);
int main()
{
        printf("before exec!\n");
        if(execlp("pro","pro","hello","world",NULL)==-1)
        {
                printf("exec failed!\n");
                perror("why");
        }
        printf("code end!\n"); 
        return 0;
}
//文件pro.c
#include <stdio.h>
int main(int argc,char *argv[])
{
        int i=0;
        printf("argc:%d\n",argc);
        printf("argv:\n");
        for(i=0;i<argc;i++)
        {
                printf("%s\n",*argv);
                argv++;
        }
        return 0;
}

实验结果与execl函数一样,区别在于execlp函数中的file参数不需要带有’/’,只需要将当前路径添加到环境变量PATH即可,如果没有添加的话,会调用失败。除此之外,还可以运行常见指令可执行文件,比如cp、pwd等。
带有v的exec族函数,包括execv, execvp, execvpe,参数argv为可执行文件所带参数指针数组。

以execv函数为例子来说明:

#include <unistd.h>
#include <stdio.h>
//函数原型:int execv(const char *path, char *const argv[]);
int main()
{
		char *argv[4]={"pro","hello","world",NULL};
        printf("before exec!\n");
        if(execv("./pro",argv)==-1)
        {
                printf("exec failed!\n");
                perror("why");
        }
        printf("code end!\n"); 
        return 0;
}
//文件pro.c
#include <stdio.h>
int main(int argc,char *argv[])
{
        int i=0;
        printf("argc:%d\n",argc);
        printf("argv:\n");
        for(i=0;i<argc;i++)
        {
                printf("%s\n",*argv);
                argv++;
        }
        return 0;
}

介绍完exec族函数,我们结合fork函数来进行应用。

例程:写一段程序,当父进程检测到输入为1的时候,创建子进程把配置文件的字段值修改掉。

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
        int data=0;
        pid_t pid;
        while(1)
        {
                scanf("%d",&data);
                if(data==1)
                {
                        pid=fork();
                        if(pid==0)
                        {
					        if(execl("./doconfig","doconfig","LENG","100",NULL)==-1)
					        {
					                printf("exec failed!\n");
									perror("why");
					        }
                        }
                }
                else
                {
                        printf("do nothing!\n");
                }
        }
        return 0;
}
//文件doconfig.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char** argv){
        int fd;
        char* find_str=malloc(128);
        char* value=malloc(128);
        if(argc!=3)
        {
                printf("arguments errors!\n");
                return -1;
        }
        strcpy(find_str,argv[1]);
        strcpy(value,argv[2]);
        fd=open("config",O_RDWR);
        if(fd==-1)
        {
                printf("no config file\n");
                return -1;
        }
        int size=lseek(fd,0,SEEK_END);
        lseek(fd,0,SEEK_SET);
        char *read_buf=(char*)malloc(sizeof(char)*size+1);
        int n_read=read(fd,read_buf,size);
        if(n_read==-1)
                printf("read fail");
        char* str_start=strstr(read_buf,find_str);
        if(str_start==NULL)
        {
                printf("no designative argument!\n");
                return -1;
        }
        str_start+=strlen(find_str)+1;
        while(1)
        {
                if(*str_start=='\n')
                        break;
                *str_start=*value;
                str_start++;
                value++;
        }
        printf("read_count:%d context:\n%s\n",n_read,read_buf);
        lseek(fd,0,SEEK_SET);
        int n_write=write(fd, read_buf, strlen(read_buf));
        if(n_write==-1)
                printf("write fail!\n");
        close(fd);
        return 0;
}
//文件config
SPEED=5
LENG=125
SCORE=75
LEVEL=95

二、system函数

功能:执行一条shell命令
函数原型:
#include <stdlib.h>
int system(const char *command);
返回:运行成功,则返回进程的状态值。当sh不能执行时,返回127。运行失败,返回-1。
参数说明:
command:shell命令字符串

在命令行执行文件的方式
1、./pro
2、sh -c ./pro

例程:通过system函数把配置文件的字段值修改掉。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
        int status=0;
        status=system("./doconfig LENG 125");
        printf("system status:%d\n",WEXITSTATUS(status));
        return 0;
}

三、popen函数

功能:执行一条shell命令,并获取执行结果
函数原型:
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
返回: FILE型指针
参数说明:
command:shell命令字符串
type:”r”—读 “w”—写

例程:编写一段代码,通过popen函数把配置文件的字段值修改掉,并获取结果存储到ret数组。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
        FILE* fp;
        char ret[1024];
        memset(ret,'\0',1024); 
        fp=popen("./doconfig LENG 125","r");
        int nread=fread(ret,1,1024,fp);
        printf("nread:%d bytes ret:%s\n",nread,ret);
        pclose(fp);
        return 0;
}

popen函数与system函数区别在于popen函数可以获取到执行结果,而system函数不可以。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 10:39:18  更:2021-09-18 10:40:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:42:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码