c - Unable to send a message from a child process back to the parent process
问题描述
I am trying to understand how pipes and forking work. So I wrote a simple program where a parent process sends a message to the child process (which works fine). But if I try to send a message back from the child process by adding the commented code, it stops working. And the execution of the program stops after outputting "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\n", msg);
/*
fprintf(out, "hi ");
printf("Child sent: hi\n");
*/
} 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\n");
/*
char msg[3];
fscanf(in, "%s", msg);
printf("Parent got: %s\n", msg);
*/
}
}
And I can't figure out why. What confuses me the most is why the child process can't even receive the message after I modified the code. Could anyone please tell me what's wrong, or direct me in the right direction?
解决方案
First solution using read/write to exchange any number of messages
Here I indicate the end of each buffer to read by a \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 != '\n');
}
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\n", 1);
rd(parent_to_child[0], 1);
wr(child_to_parent[1], "fine, and you ?\n", 1);
rd(parent_to_child[0], 1);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
wr(parent_to_child[1], "hello\n", 0);
rd(child_to_parent[0], 0);
wr(parent_to_child[1], "how are you ?\n", 0);
rd(child_to_parent[0], 0);
wr(parent_to_child[1], "fine too\n", 0);
}
}
Compilation and execution :
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
It is also possible to use fread/fwrite, fflush is necessary after fwrite to not be blocked. It is fortunately not necessary to close the pipe after sending to be able to read and answer, else only one message can be exchanged. I still use \n to indicate the end of the buffer sent :
#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 != '\n');
}
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\n", 1);
rd(in, 1);
wr(out, "fine, and you ?\n", 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\n", 0);
rd(in, 0);
wr(out, "how are you ?\n", 0);
rd(in, 0);
wr(out, "fine too\n", 0);
}
}
Compilation and execution:
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
And finally if you want to use fscanf("%s", ...)
you need to sent a separator (a space or \n for instance) after the word to not block fscanf and of course to also read the separator character, the fflush is necessary after the fwrite.
If I change a little you program :
#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\n", msg);
fprintf(out, "hi ");
fflush(out);
printf("Child sent: hi\n");
fscanf(in ,"%s%c", msg, &c);
printf("Child got: %s\n", msg);
fprintf(out, "fine,you? ");
fflush(out);
printf("Child sent: fine,you?\n");
fscanf(in ,"%s%c", msg, &c);
printf("Child got: %s\n", 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\n");
fflush(out);
printf("Parent sent: hello\n");
char msg[16], c;
fscanf(in, "%s%c", msg, &c);
printf("Parent got: %s\n", msg);
fprintf(out, "how-are-you? ");
fflush(out);
printf("Parent sent: how-are-you?\n");
fscanf(in, "%s%c", msg, &c);
printf("Parent got: %s\n", msg);
fprintf(out, "fine-too ");
fflush(out);
printf("Parent sent: fine-too\n");
}
}
Compilation and execution :
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
推荐阅读
- php - 从 PHP HTTP 客户端调用托管在 Amazon 上的 API 时连接被拒绝
- sql - 当连续序列中的“空心”跟随时,如何标记记录?
- laravel - 在没有 ?page=2 的情况下在 laravel 6 中设置当前页面分页
- sql - SQL Server:根据多个条件在组中搜索
- java - Hibernate InheritanceType.JOINED 阻止创建表
- python - 在 Python 中,这个表达式“(a is b) == ( id(a) == id(b) )” 总是返回 True 吗?
- elixir - 如何使用 protobuf 文件生成长生不老药代码?
- c# - 将excel文件读入datagridview c#
- mysql - 如何将语法结果转换为变量mysql
- c++ - C++ atomic variables cannot be assigned to each other: why? is it possible to?