在 C 中创建管道用于多个进程之间的进程间通信
Creating pipes in C for inter process communication between multiple processes
这个问题已经有多个答案,但是 none 已经能够帮助我解决我的问题。我试图在 C 中使用匿名管道来理解 IPC。
根据我对管道的理解,它们是一种单向通信通道,具有一个读取端和一个写入端。
假设我们有两个 c 文件,一个名为 parent.c,另一个名为 child.c。我想要实现的是能够创建 5 个或更多子进程。在此之后,父进程和子进程应该通过标准输入和 standard output
与子进程通信,但由于我希望能够打印父进程从子进程接收到的内容,我将改为将管道连接到 [=14] =] 使用 dup2
输出。
总结
1. 运行 一个启动 5 个或更多子进程并运行它们的父程序。
2. 子进程使用 scanf
.
等待父进程的输入
3.父进程给子进程发送消息
4. 子进程收到消息并向父进程发送回复并退出。
5.父进程打印接收到的消息并打印退出。
parent.c
// Parentc
#include <stdio.h>
#include <stdlib.h>
#include <uinstd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, const char *argv[]){
// File descriptors for the pipes
int read_pipe[2]; // From child to parent
int write_pipe[2]; // From parent to child
pid_t process_id;
int exit_status;
// Try to fork 5 child processes
for(int i = 0; i < 5; i++){
if(pipe(write_pipe) == -1 || pipe(read_pipe) == -1){
perror("Pipe");
exit(1);
}
// Spin a child process
process_id = fork();
if(process_id == -1){
perror("Fork");
exit(1);
} else if(processId == 0) {
// The child process
// I don't know what to do here, The idea is to close the
// unneeded end of the pipes and wait for input from the parent
// process
// Start the ./child
execl("./child", "");
} else {
// The parent process
char recieved_data[1024];
// Send data to child since stderr is duplicated in the pipe
// It sends the pid of the child
fprintf(stderr, "Test data to %d ", process_id);
// Wait to recieve data from child
// Don't know how to do that
// Print the recieved data
printf("Parent recieved: \"%s\"\n", recieved_data);
wait(&exit_status); // Will wait till all children exit before exiting
}
}
return 0;
}
child.c是一个简单的程序,如下图
child.c
#include <stdio.h>
int main(int argc, const char *argv[]){
char data_buffer[1024];
// Wait for input from parent
scanf("%s", data_buffer);
// Send data back to parent
printf("Child process: %s", data_buffer);
return 0;
}
Expected output
$ ./parent
parent recived: "Child process: Test data to 12345"
parent recived: "Child process: Test data to 12346"
parent recived: "Child process: Test data to 12347"
parent recived: "Child process: Test data to 12348"
parent recived: "Child process: Test data to 12349"
其中12345、12346....12349是子进程的进程id
这里有我做的代码,我会用它来向你解释:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char buff[1024];
int aux, i, count;
int fds[2], fdss[2];
pipe(fds); //Here we initialize the file descriptors
pipe(fdss);
mode_t fd_mode = S_IRWXU;
for (i = 0; i < 3; i++) {
aux = fork();
if (aux == 0)
break;
}
switch (i) {
case 0:
printf("Write something:\n");
scanf("%s[^\n]", buff);
i = 0;
count = 0;
while(buff[i] != '[=10=]') {
count++;
i++;
}
dup2(fds[1], 1);
close(fds[1]);
close(fds[0]);
close(fdss[0]);
close(fdss[1]);
write (1, buff, sizeof(buff));
break;
case 1:
dup2(fds[0], 0);
dup2(fdss[1], 1);
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
//
if (execl("/bin/grep", "grep", "example", NULL) == -1) {
printf("Error\n");
exit (1);
}
break;
case 2:
aux = open("result.txt", O_RDWR | O_CREAT , S_IRWXU);
dup2(fdss[0], 0);
dup2(aux, 1);
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
close(aux);
if (execl("/usr/bin/wc", "wc", "-l", NULL) == -1) {
printf("Error \n");
exit (1);
}
}
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
for (i = 0; i < 3; i++) wait(NULL);
return 0;
}
好的,让我们开始吧:
我们使用 pipe() 创建和初始化管道
然后我们编写我们的代码,在 execl() 之前我们更改文件描述符,以便通过进程传递我们将在控制台中写入的文本,最后将 [=15] 的结果写入名为 result.txt 的文件中=] 命令应用于我们编写的文本。
函数 dup2(new_descriptor, old_descriptor) 正在将新描述符复制到旧描述符中并关闭旧描述符。例如:
在 dup2(fds[1], 1) 之前我们有:
0 标准输入
1 个标准输出
2 标准错误
在 dup2(fds[1], 1) 之后我们有:
0 标准输入
1 个 fds[1]
2 标准错误
注意:如果你不想使用 1,你可以简单地写 STDOUT_FILENO
所以现在我们可以通过进程写入,在我的示例中也可以写入文件
这个问题已经有多个答案,但是 none 已经能够帮助我解决我的问题。我试图在 C 中使用匿名管道来理解 IPC。
根据我对管道的理解,它们是一种单向通信通道,具有一个读取端和一个写入端。
假设我们有两个 c 文件,一个名为 parent.c,另一个名为 child.c。我想要实现的是能够创建 5 个或更多子进程。在此之后,父进程和子进程应该通过标准输入和 standard output
与子进程通信,但由于我希望能够打印父进程从子进程接收到的内容,我将改为将管道连接到 [=14] =] 使用 dup2
输出。
总结
1. 运行 一个启动 5 个或更多子进程并运行它们的父程序。
2. 子进程使用 scanf
.
等待父进程的输入
3.父进程给子进程发送消息
4. 子进程收到消息并向父进程发送回复并退出。
5.父进程打印接收到的消息并打印退出。
parent.c
// Parentc
#include <stdio.h>
#include <stdlib.h>
#include <uinstd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, const char *argv[]){
// File descriptors for the pipes
int read_pipe[2]; // From child to parent
int write_pipe[2]; // From parent to child
pid_t process_id;
int exit_status;
// Try to fork 5 child processes
for(int i = 0; i < 5; i++){
if(pipe(write_pipe) == -1 || pipe(read_pipe) == -1){
perror("Pipe");
exit(1);
}
// Spin a child process
process_id = fork();
if(process_id == -1){
perror("Fork");
exit(1);
} else if(processId == 0) {
// The child process
// I don't know what to do here, The idea is to close the
// unneeded end of the pipes and wait for input from the parent
// process
// Start the ./child
execl("./child", "");
} else {
// The parent process
char recieved_data[1024];
// Send data to child since stderr is duplicated in the pipe
// It sends the pid of the child
fprintf(stderr, "Test data to %d ", process_id);
// Wait to recieve data from child
// Don't know how to do that
// Print the recieved data
printf("Parent recieved: \"%s\"\n", recieved_data);
wait(&exit_status); // Will wait till all children exit before exiting
}
}
return 0;
}
child.c是一个简单的程序,如下图
child.c
#include <stdio.h>
int main(int argc, const char *argv[]){
char data_buffer[1024];
// Wait for input from parent
scanf("%s", data_buffer);
// Send data back to parent
printf("Child process: %s", data_buffer);
return 0;
}
Expected output
$ ./parent
parent recived: "Child process: Test data to 12345"
parent recived: "Child process: Test data to 12346"
parent recived: "Child process: Test data to 12347"
parent recived: "Child process: Test data to 12348"
parent recived: "Child process: Test data to 12349"
其中12345、12346....12349是子进程的进程id
这里有我做的代码,我会用它来向你解释:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char buff[1024];
int aux, i, count;
int fds[2], fdss[2];
pipe(fds); //Here we initialize the file descriptors
pipe(fdss);
mode_t fd_mode = S_IRWXU;
for (i = 0; i < 3; i++) {
aux = fork();
if (aux == 0)
break;
}
switch (i) {
case 0:
printf("Write something:\n");
scanf("%s[^\n]", buff);
i = 0;
count = 0;
while(buff[i] != '[=10=]') {
count++;
i++;
}
dup2(fds[1], 1);
close(fds[1]);
close(fds[0]);
close(fdss[0]);
close(fdss[1]);
write (1, buff, sizeof(buff));
break;
case 1:
dup2(fds[0], 0);
dup2(fdss[1], 1);
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
//
if (execl("/bin/grep", "grep", "example", NULL) == -1) {
printf("Error\n");
exit (1);
}
break;
case 2:
aux = open("result.txt", O_RDWR | O_CREAT , S_IRWXU);
dup2(fdss[0], 0);
dup2(aux, 1);
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
close(aux);
if (execl("/usr/bin/wc", "wc", "-l", NULL) == -1) {
printf("Error \n");
exit (1);
}
}
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
for (i = 0; i < 3; i++) wait(NULL);
return 0;
}
好的,让我们开始吧: 我们使用 pipe() 创建和初始化管道 然后我们编写我们的代码,在 execl() 之前我们更改文件描述符,以便通过进程传递我们将在控制台中写入的文本,最后将 [=15] 的结果写入名为 result.txt 的文件中=] 命令应用于我们编写的文本。 函数 dup2(new_descriptor, old_descriptor) 正在将新描述符复制到旧描述符中并关闭旧描述符。例如: 在 dup2(fds[1], 1) 之前我们有: 0 标准输入 1 个标准输出 2 标准错误 在 dup2(fds[1], 1) 之后我们有: 0 标准输入 1 个 fds[1] 2 标准错误 注意:如果你不想使用 1,你可以简单地写 STDOUT_FILENO 所以现在我们可以通过进程写入,在我的示例中也可以写入文件