了解管道、重定向和IPC
我是管道新手,一直在尝试创建一对管道,允许子进程写入父进程,父进程返回通信。一位家长最多有4个孩子。使用exec,子程序将变成不同的程序 我的工作内容: 从父进程写入子进程。当我读入子程序的stdin时,它将收到我从父程序写入的内容 目标: 创建一个纸牌游戏,其中家长与每个单独的客户(子进程)交谈,并向他们提供所有的动作和信息,从其stdout到孩子的stdin。单个子进程在其标准输出上返回其移动,由主父进程读取。游戏的动作完全由一个序列决定,而不是由玩家决定。所以这是一个机器人游戏 我的困境: 我不知道如何获取它,以便家长可以通过文件流读取孩子的标准输出。当我试图设置从子行读取时,代码似乎停止工作。甚至孩子也不能从父母那里读东西(它似乎停止在现在注释掉的用于设置孩子到父母的留置权上) 我也不知道如何“等待”直到有东西出现。比如,在开始时,玩家必须向家长发送“准备就绪”消息,让他们知道自己正在工作。一旦我从孩子那里发送了“就绪”,我如何无限期地“等待”直到下一条消息出现 我不确定我是否正确安装了管道。有人能提供如何使用通信管道的指导,并确认我下面的逻辑吗 为了让父母写信给孩子,我收集了以下信息:了解管道、重定向和IPC,c,linux,pipe,C,Linux,Pipe,我是管道新手,一直在尝试创建一对管道,允许子进程写入父进程,父进程返回通信。一位家长最多有4个孩子。使用exec,子程序将变成不同的程序 我的工作内容: 从父进程写入子进程。当我读入子程序的stdin时,它将收到我从父程序写入的内容 目标: 创建一个纸牌游戏,其中家长与每个单独的客户(子进程)交谈,并向他们提供所有的动作和信息,从其stdout到孩子的stdin。单个子进程在其标准输出上返回其移动,由主父进程读取。游戏的动作完全由一个序列决定,而不是由玩家决定。所以这是一个机器人游戏 我的困境:
void start_child_process(Game *game, int position) {
int child2Parent[2];
int parent2Child[2];
if (pipe(parent2Child)) {
printf("PIPE FAIL!\n");
}
if (pipe(child2Parent)) {
printf("PIPE FAIL!\n");
}
pid_t pid = fork();
game->readStream[position] = fdopen(child2Parent[0], "r");
game->writeStream[position] = fdopen(parent2Child[1], "w");
if (pid) { // Parent
// Write from parent to child
close(parent2Child[0]);
dup2(fileno(game->writeStream[position]), STDOUT_FILENO);
fprintf(game->writeStream[position], "%s", "test message");
fflush(game->writeStream[position]);
close(parent2Child[1]);
// Read from child -- not working
/*dup2(child2Parent[0], STDIN_FILENO);
close(child2Parent[0]);
close(child2Parent[1]);
*/
} else {
// Setup child to read from stdin from parent
dup2(parent2Child[0], STDIN_FILENO);
close(parent2Child[1]);
// Setup writing from child to parent
/*
if (dup2(child2Parent[1], STDOUT_FILENO) == -1) {
fprintf(stderr, "dup2 in child failed\n");
} else {
fprintf(stderr, "dup2 in child successful\n");
close(child2Parent[0]);
close(child2Parent[1]);
}
*/
if ((int)execl("child", "2", "A", NULL) == -1) {
printf("Failed child process\n");
}
}
}
char string[100];
printf("reading from pipe: %s\n", fgets(string, 100, stdin));
但我不知道怎么做
此外,我不允许使用popen()或write()。显然,我也被鼓励使用文件流。我主要谈论的是在父进程和子进程之间建立双向通信的主要问题。如果您想要更多的答案,请提出单独的问题 您似乎有一个合理的通用方法,但您确实有一个严重的误解/设计缺陷:多个客户端将其标准流连接到管道以与父进程通信是合理的,如果希望一次能够处理多个客户端,则无法将所有这些管道的父端连接到父端的标准流。毕竟,父级只有一组标准流。为了支持多个客户端,父进程必须为每个客户端维护一对单独的文件描述符和/或流,并且必须通过这些描述符和/或流而不是通过其标准流进行通信 我不确定为什么当你把孩子和父母联系起来时,你的父母/孩子之间的沟通会失败。这个过程实际上类似于设置另一个端点。以下是一个工作示例:
家长c:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int main() {
int child2Parent[2];
int parent2Child[2];
char buffer[256];
FILE *p2cStream;
FILE *c2pStream;
pid_t pid;
if (pipe(parent2Child) || pipe(child2Parent)) {
perror("Failed to create pipes");
exit(EXIT_FAILURE);
}
switch (pid = fork()) {
case -1: /* error */
perror("Failed to fork");
break;
case 0: /* child */
// Setup child to read from stdin from parent
close(parent2Child[1]); /* ignoring any error */
close(child2Parent[0]); /* ignoring any error */
if ((dup2(parent2Child[0], STDIN_FILENO) < 0)
|| (dup2(child2Parent[1], STDOUT_FILENO) < 0)) {
perror("Failed to duplicate file descriptors");
} else {
/* conventionally, the first program argument is the program name */
/* also, execl() returns only if it fails */
execl("child", "child", "2", "A", NULL);
perror("Failed to exec child process");
}
exit(EXIT_FAILURE);
break;
default: /* parent */
close(parent2Child[0]); /* ignoring any error */
close(child2Parent[1]); /* ignoring any error */
if (!(p2cStream = fdopen(parent2Child[1], "w"))
|| !(c2pStream = fdopen(child2Parent[0], "r"))) {
perror("Failed to open streams");
exit(EXIT_FAILURE);
}
if ((fprintf(p2cStream, "test message from parent\n") < 0)
|| fclose(p2cStream)) {
perror("Failed to write to the child");
exit(EXIT_FAILURE);
}
if (fscanf(c2pStream, "%255[^\n]", buffer) < 1) {
perror("Failed to read the child's message");
exit(EXIT_FAILURE);
}
printf("The child responds: '%s'\n", buffer); /* ignoring any error */
break;
}
return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
int main(){
int child2Parent[2];
int parent2儿童[2];
字符缓冲区[256];
文件*p2cStream;
文件*c2pStream;
pid_t pid;
if(管道(家长2孩子)| |管道(家长2孩子)){
perror(“未能创建管道”);
退出(退出失败);
}
开关(pid=fork()){
案例-1:/*错误*/
perror(“未能分叉”);
打破
案例0:/*儿童*/
//将子项设置为从父项读取标准数据
关闭(parent2Child[1]);/*忽略任何错误*/
关闭(child2Parent[0]);/*忽略任何错误*/
if((dup2(parent2Child[0],STDIN_FILENO)<0)
||(dup2(child2Parent[1],STDOUT_FILENO)<0){
perror(“未能复制文件描述符”);
}否则{
/*按照惯例,第一个程序参数是程序名*/
/*此外,execl()仅在失败时返回*/
execl(“child”、“child”、“2”、“A”、NULL);
perror(“未能执行子进程”);
}
退出(退出失败);
打破
默认值:/*父级*/
关闭(parent2Child[0]);/*忽略任何错误*/
关闭(child2Parent[1]);/*忽略任何错误*/
如果(!(p2cStream=fdopen(parent2Child[1],“w”))
||!(c2pStream=fdopen(child2Parent[0],“r”)){
perror(“未能打开流”);
退出(退出失败);
}
if((fprintf(p2cStream,“来自父级的测试消息”)<0)
||fclose(p2cStream)){
perror(“未能给孩子写信”);
退出(退出失败);
}
if(fscanf(c2pStream,“%255[^\n]”,缓冲区)<1){
perror(“未能阅读孩子的信息”);
退出(退出失败);
}
printf(“子响应:'%s'\n',缓冲区);/*忽略任何错误*/
打破
}
返回退出成功;
}
c.儿童:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
char buffer[256] = { 0 };
if (scanf("%255[^\n]", buffer) < 0) {
perror("Failed to reading input");
exit(EXIT_FAILURE);
}
/*
* If stdout is connected to the parent then we must avoid
* writing anything unexpected to it
*/
if (fprintf(stderr, "received: '%s'\n", buffer) < 0) {
perror("Failed to echo input");
exit(EXIT_FAILURE);
}
printf("Hi, Mom!\n"); /* ignoring any error */
fflush(stdout); /* ignoring any error */
return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
int main(int argc,char*argv[]){
字符缓冲区[256]={0};
如果(扫描(“%255[^\n]”,缓冲区)<0){
perror(“读取输入失败”);
退出(退出失败);
}
/*
*如果stdout连接到父级,那么我们可以