无法将子进程发送回父进程的消息
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无法将子进程发送回父进程的消息相关的知识,希望对你有一定的参考价值。
我试图了解管道和分叉是如何工作的。所以我编写了一个简单的程序,其中父进程向子进程发送消息(工作正常)。但是,如果我尝试通过添加注释代码从子进程发回消息,它将停止工作。输出“Parent sent:hello”后程序的执行停止。
int main() {
int child_to_parent[2];
int parent_to_child[2];
pipe(child_to_parent);
pipe(parent_to_child);
pid_t id = fork();
if (id == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
FILE* out = fdopen(child_to_parent[1], "w");
FILE* in = fdopen(parent_to_child[0], "r");
char msg[6];
fscanf(in ,"%s", msg);
printf("Child got: %s
", msg);
/*
fprintf(out, "hi ");
printf("Child sent: hi
");
*/
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
FILE* in = fdopen(child_to_parent[0], "r");
FILE* out = fdopen(parent_to_child[1], "w");
fprintf(out, "hello");
printf("Parent sent: hello
");
/*
char msg[3];
fscanf(in, "%s", msg);
printf("Parent got: %s
", msg);
*/
}
}
我无法弄清楚原因。令我困惑的是为什么在修改代码后子进程甚至无法接收消息。谁能告诉我什么是错的,或者指引我朝着正确的方向前进?
第一种使用读/写交换任意数量消息的解决方案
在这里,我指出要通过 n读取的每个缓冲区的结尾:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void rd(int fd, int child)
{
char c;
int first = 1;
do {
if (!read(fd, &c, 1))
break;
if (first) {
printf("%s got:", (child) ? "Child" : "Parent");
first = 0;
}
putchar(c);
} while (c != '
');
}
void wr(int fd, const char * msg, int child)
{
write(fd, msg, strlen(msg));
printf("%s sent:%s", (child) ? "Child" : "Parent", msg);
}
int main() {
int child_to_parent[2];
int parent_to_child[2];
pipe(child_to_parent);
pipe(parent_to_child);
pid_t id = fork();
if (id == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
rd(parent_to_child[0], 1);
wr(child_to_parent[1], "hi
", 1);
rd(parent_to_child[0], 1);
wr(child_to_parent[1], "fine, and you ?
", 1);
rd(parent_to_child[0], 1);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
wr(parent_to_child[1], "hello
", 0);
rd(child_to_parent[0], 0);
wr(parent_to_child[1], "how are you ?
", 0);
rd(child_to_parent[0], 0);
wr(parent_to_child[1], "fine too
", 0);
}
}
编译和执行:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra p.c
pi@raspberrypi:/tmp $ ./a.out
Parent sent:hello
Child got:hello
Child sent:hi
Parent got:hi
Parent sent:how are you ?
Child got:how are you ?
Child sent:fine, and you ?
Parent got:fine, and you ?
Parent sent:fine too
Child got:fine too
也可以使用fread / fwrite,在fwrite之后fflush是必要的,不被阻止。幸运的是,发送后无需关闭管道以便能够读取和回答,否则只能交换一条消息。我仍然使用 n来表示发送缓冲区的结尾:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void rd(FILE * fd, int child)
{
char c;
int first = 1;
do {
if (!fread(&c, 1, 1, fd))
break;
if (first) {
printf("%s got:", (child) ? "Child" : "Parent");
first = 0;
}
putchar(c);
} while (c != '
');
}
void wr(FILE * fd, const char * msg, int child)
{
fwrite(msg, strlen(msg), 1, fd);
fflush(fd);
printf("%s sent:%s", (child) ? "Child" : "Parent", msg);
}
int main() {
int child_to_parent[2];
int parent_to_child[2];
pipe(child_to_parent);
pipe(parent_to_child);
pid_t id = fork();
if (id == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
FILE* out = fdopen(child_to_parent[1], "w");
FILE* in = fdopen(parent_to_child[0], "r");
rd(in, 1);
wr(out, "hi
", 1);
rd(in, 1);
wr(out, "fine, and you ?
", 1);
rd(in, 1);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
FILE* in = fdopen(child_to_parent[0], "r");
FILE* out = fdopen(parent_to_child[1], "w");
wr(out, "hello
", 0);
rd(in, 0);
wr(out, "how are you ?
", 0);
rd(in, 0);
wr(out, "fine too
", 0);
}
}
编译和执行:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra pp.c
pi@raspberrypi:/tmp $ ./a.out
Parent sent:hello
Child got:hello
Child sent:hi
Parent got:hi
Parent sent:how are you ?
Child got:how are you ?
Child sent:fine, and you ?
Parent got:fine, and you ?
Parent sent:fine too
Child got:fine too
最后,如果你想使用fscanf("%s", ...)
,你需要在单词之后发送一个分隔符(例如空格或 n)来阻止fscanf,当然还要读取分隔符,fflrite之后需要fflush。
如果我改变了一点你编程:
#include <stdio.h>
#include <unistd.h>
int main() {
int child_to_parent[2];
int parent_to_child[2];
pipe(child_to_parent);
pipe(parent_to_child);
pid_t id = fork();
if (id == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
FILE* out = fdopen(child_to_parent[1], "w");
FILE* in = fdopen(parent_to_child[0], "r");
char msg[16], c;
fscanf(in ,"%s%c", msg, &c);
printf("Child got: %s
", msg);
fprintf(out, "hi ");
fflush(out);
printf("Child sent: hi
");
fscanf(in ,"%s%c", msg, &c);
printf("Child got: %s
", msg);
fprintf(out, "fine,you? ");
fflush(out);
printf("Child sent: fine,you?
");
fscanf(in ,"%s%c", msg, &c);
printf("Child got: %s
", msg);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
FILE* in = fdopen(child_to_parent[0], "r");
FILE* out = fdopen(parent_to_child[1], "w");
fprintf(out, "hello
");
fflush(out);
printf("Parent sent: hello
");
char msg[16], c;
fscanf(in, "%s%c", msg, &c);
printf("Parent got: %s
", msg);
fprintf(out, "how-are-you? ");
fflush(out);
printf("Parent sent: how-are-you?
");
fscanf(in, "%s%c", msg, &c);
printf("Parent got: %s
", msg);
fprintf(out, "fine-too ");
fflush(out);
printf("Parent sent: fine-too
");
}
}
编译和执行:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra ppp.c
pi@raspberrypi:/tmp $ ./a.out
Parent sent: hello
Child got: hello
Child sent: hi
Parent got: hi
Parent sent: how-are-you?
Child got: how-are-you?
Child sent: fine,you?
Parent got: fine,you?
Parent sent: fine-too
Child got: fine-too
fscanf
读取,直到你使用isspace
找到一些空白字符(由%s
给出),但你没有发送一个。所以fscanf
永远不会回来,因为它正在等待空白。
使用fread
和fwrite
而不是fscanf
和fprintf
,你的管道将起作用。
在父级和子级中,当您完成对管道的写入后,使用fflush
刷新缓冲区并使用close
关闭管道写入结束。
这是一个略微修改的程序:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
FILE *fdopen(int fd, const char *mode);
int main() {
int child_to_parent[2];
int parent_to_child[2];
pipe(child_to_parent);
pipe(parent_to_child);
pid_t id = fork();
if (id == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
FILE* out = fdopen(child_to_parent[1], "w");
FILE* in = fdopen(parent_to_child[0], "r");
char msg[6];
printf("Child gonna read...
");
fscanf(in ,"%s", msg);
printf("Child got: %s
", msg);
fprintf(out, "hi");
fflush(out);
printf("Child sent: hi
");
close(child_to_parent[1]);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
FILE* in = fdopen(child_to_parent[0], "r");
FILE* out = fdopen(parent_to_child[1], "w");
fprintf(out, "hello");
printf("Parent sent: hello
");
fflush(out);
close(parent_to_child[1]);
char msg[3];
printf("Parent gonna read...
");
fscanf(in, "%s", msg);
printf("Parent got: %s
", msg);
}
}
运行时的输出:
Parent sent: hello
Parent gonna read...
Child gonna read...
Child got: hello
Child sent: hi
Parent got: hi
以上是关于无法将子进程发送回父进程的消息的主要内容,如果未能解决你的问题,请参考以下文章
Linux - 从管道读取的孩子接收发送到标准输出的调试消息