C++中实现子进程执行和管道通信详解
作者:Silent_Blue_Sky
简介
在这篇博客中,我们将深入探索如何在 C++ 程序中实现子进程的创建与执行,以及父子进程间的管道通信。核心代码提供了一个框架,用于接收用户命令、创建子进程并利用 execvp 系统调用执行这些命令。此外,我们通过创建管道(pipe),展示了如何在父子进程间安全地传递数据。
本文重点介绍 fork, pipe, 和 execvp 的使用方法,并解释了如何将标准输出和标准错误从子进程重定向到父进程。这一过程涉及对 Unix 系统调用的深入理解,尤其是进程间通信(IPC)的概念。我们的目标是提供一个清晰的指南,帮助读者理解和实现在现代操作系统中广泛应用的进程创建、执行和通信机制。
该教程适合对操作系统、进程管理以及 Unix/Linux 系统编程感兴趣的读者。无论是系统编程新手还是有经验的开发者,都可以通过这个实例加深对进程间通信和命令行界面(CLI)应用编程的理解。
exec相关
一共有六个分三组记忆
execlp -> execvp
execl -> execv
execle -> execve
这几个函数的速记
记忆口诀如下:
0、exec是通用前缀
1、 p 代表第一个参数是file 也就是程序的名字比如 ls, 如果名字没带p, 代表第一个参数是path, 比如 /bin/ls
2、 l 代表参数传递的是list, 参数是一个个传递的,最后一个参数为NULL
3、 v 代表argv, 参数是用char* 数组传递的
4、 e 代表环境变量
execlp l->list,p-> file 参数就是(file, a1, a2, a3,..., NULL);
execvp v->argv,p->file. 参数就是file, aegv)
execl l->list,没p -> path 参数就是(path, a1, a2, a3, ..., NULL);
execv v->argv,没p->path 参数(path, argv);
execle l->list,没p->path, e->env 参数(path, a0, a1, ..., NULL, env);
execve v->aegv,没p->path, e->env 参数(path, argv, env);
实战代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <string.h> #include <iostream> #include <string> bool isCommandSupport(std::string command) { if (command == "ls" || command == "pwd" || command == "ps" || command == "cat" || command == "grep" || command == "wc" || command == "exit") { return true; } return false; } void childTask() { while (true) { // 获得一整行输入 std::string line; size_t len = 0; std::getline(std::cin, line); // 进行分割 char *p = strtok((char *) line.c_str(), " "); char *argv[100]; int argc = 0; while (p != NULL) { argv[argc++] = p; p = strtok(NULL, " "); } argv[argc] = NULL; if (argc == 0) { continue; } if (isCommandSupport(argv[0])) { if (strcmp(argv[0], "exit") == 0) { exit(0); } } else { printf("command not support\n"); continue; } int pipefd[2]; pid_t pid; char buf; if (pipe(pipefd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (pid == 0) { /* 子进程 */ close(pipefd[0]); // 关闭读端 dup2(pipefd[1], STDOUT_FILENO); // 将标准输出重定向到管道写端 dup2(pipefd[1], STDERR_FILENO); // 将标准错误也重定向到管道写端 close(pipefd[1]); // 关闭原始写端 execvp(argv[0], argv); _exit(EXIT_FAILURE); } else { /* 父进程 */ close(pipefd[1]); // 关闭写端 while (read(pipefd[0], &buf, 1) > 0) { write(STDOUT_FILENO, &buf, 1); } close(pipefd[0]); // 关闭读端 int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { } else if (WIFSIGNALED(status)) { printf("child terminated abnormally, signal %d\n", WTERMSIG(status)); } } } } int main() { childTask(); }
到此这篇关于C++中实现子进程执行和管道通信详解的文章就介绍到这了,更多相关C++子进程执行和管道通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!