[英]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.