[英]Writing and reading messages continuously in ipc with pipes in C
我编写了一个程序,其中父进程创建了两个子进程。 父进程写入第一个或第二个子进程,子进程读取消息。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main(){
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a,child_b;
if(pipe(p1) == -1){
printf("error in creating pipe\n");
exit(-1);
}
if(pipe(p2) == -1){
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO,msgbuf,MSGSIZE);
printf("%d receives message: %s\n",getpid(),msgbuf);
close(p1[0]);
close(p1[1]);
} else {
child_b = fork();
if (child_b == 0) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO,msgbuf,MSGSIZE);
printf("%d receives message: %s\n",getpid(),msgbuf);
close(p2[0]);
close(p2[1]);
} else {
/* Parent Code */
// Write something to child A
while(1){
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s",&choice,msgbuf);
switch(choice){
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
// Write something to child B
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
case -1:
usleep(250);
printf("parent waiting");
wait(NULL);
exit(-1);
break;
}
}
}
}
return 0;
}
我的问题是我希望父进程继续写入子进程。 使用上面的代码,一旦它写入 child 或 child 2,它就不会再次写入或至少子进程不会再次读取它。 我不知道是否有可能做到这一点。
我尝试将 while 循环放在程序的开头,但这会导致每次都创建另一个子进程。
这是我的解决方案,然后是一些解释:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
#define MSGSIZE 64
void read_process(int fh) {
assert(-1 < fh);
char msgbuf[MSGSIZE];
ssize_t retval = 0;
while (-1 < retval) {
retval = read(fh, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(fh);
}
}
void write_process(int fh_child_1, int fh_child_2) {
assert(-1 < fh_child_1);
assert(-1 < fh_child_2);
char msgbuf[MSGSIZE];
int choice = -1;
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %64s", &choice, msgbuf);
switch (choice) {
case 1:
write(fh_child_1, msgbuf, MSGSIZE);
break;
// Write something to child B
case 2:
write(fh_child_2, msgbuf, MSGSIZE);
break;
case -1:
printf("parent waiting");
wait(NULL);
exit(-1);
break;
}
}
}
int main() {
/* 0 will be for reading, 1 for writing */
int p1[2];
int p2[2];
pid_t pid;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
/* Don't create 2nd pipe yet, we don't require it here and save us to
* tear it down in child 1 */
pid = fork();
if (pid == 0) {
close(p1[1]); /* not needed here */
p1[1] = -1;
read_process(p1[0]);
exit(EXIT_SUCCESS);
} else {
/* Nobody is going to read from pipe 1 here again */
close(p1[0]);
p1[0] = -1; /* Mark fh as invalid */
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
pid = fork();
if (pid == 0) {
close(p1[1]);
p1[1] = -1;
close(p2[1]);
p2[1] = -1;
/* Ensure we did not forget an fh */
assert(-1 == p1[0]);
assert(-1 == p1[1]);
assert(-1 == p2[1]);
read_process(p2[0]);
exit(EXIT_SUCCESS);
} else {
/* Parent Code */
close(p2[0]);
p2[0] = -1;
assert(-1 == p1[0]);
assert(-1 == p2[0]);
write_process(p1[1], p2[1]);
exit(EXIT_SUCCESS);
}
}
return 0;
}
如前所述,您的主要问题是您的子进程不会循环,而是只读取一次。
有几个注意事项,我先说一般的,然后再说更多的系统编程特定的。
您的主要问题,丢失的循环,隐藏在您的代码之下,有点像意大利面。
C 提供了构建代码的方法,例如函数。 函数不仅用于重用代码,还可以用于总结您的代码:不要将子进程的代码直接粘贴到您需要的地方,而是将代码转移到专用函数并调用该函数。 这对理解代码的基本结构有很大帮助:
close(p1[1]); /* not needed here */
p1[1] = -1;
read_process(p1[0]);
exit(EXIT_SUCCESS);
很明显,基本思想是什么,不是吗? 如果您想了解读取过程的详细信息,请检查read_process
函数。
小心你的资源。 仅在需要时才分配尽可能少的资源。 尽快释放它们并将它们标记为已释放 - 请参阅管道文件句柄。
最后,如果你fork,这个过程基本上是复制的。 您创建了第二个进程,并为它提供了所有(好吧,大多数)父进程资源的副本/克隆。
您的情况下的文件句柄是克隆的。 例如关闭p1[0]
在你的孩子不影响p1[0]
在您的父母,因为他们是不一样的。 这也意味着,在分叉之后,您应该立即考虑所有可用资源,并立即删除您不需要的所有资源,例如
pid = fork();
if(0 == pid) {
close(p1[1]); /* not needed here */
p1[1] = -1;
read_process(p1[0]);
exit(EXIT_SUCCESS);
}
你的第一个孩子不需要p1[1]
,因此关闭它并将其标记为关闭和无效。
可能还有很多话要说,但这些是我立即想到的要点。
其中一些可能看起来并不笨拙,但是随着您越来越有经验,并且您的代码库不断增长,您会欣赏这些东西,至少我每天做的事情越来越多。 至于代码,当然还有很多错误隐藏在那里,尽管我希望你明白基本的想法;)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.