使用两个管道的双向消息传递中的 SIGPIPE
SIGPIPE in bidirectional messaging with two pipes
你好,我要开发这个程序来创建 4 children,然后依次让它们做一个简单的操作。第一个做加法,第二个做其余的,第三个做乘法,第四个做除法。父亲将他希望children到"calculate"的两个数字的字符串写在套接字上,每个children都应该读取这个字符串,提取数字并进行操作。显然,作为两个管道,需要父亲每次都写入字符串,因为在 child 中读取。我真的不明白为什么在第二次迭代时,我收到了父亲写的 SIGPIPE。有人可以向我解释为什么吗?我在调试上浪费了 3 天,但我什么也没找到。非常感谢。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
/*
fd_0 padre escribe y hijo lee ==== padre cierra fd_0[0] y hijo cierra fd_0[1]
fd_1 hijo escribe y padre lee === padre cierra fd_1[1] y hijo cierra fd_1[0]
*/
int main (int argc, char * argv[]){
char * str = malloc(100*sizeof(char));//hijo
char readbuffer_h[150];
char * stringa = malloc(100*sizeof(char));//padre
char readbuffer_p[150];
int a,b;
int x,y;
int n = 4;
int i,status,nbytes, pipe_status;
int pid, ppid,yo,padre;
int fd_0[2], fd_1[2] ;
pipe_status=pipe(fd_0);
if(pipe_status==- 1) {
perror("Error creando la tuberia 0\n");
exit(EXIT_FAILURE);
}
pipe_status=pipe(fd_1);
if(pipe_status== -1) {
perror("Error creando la tuberia 1 \n");
exit(EXIT_FAILURE);
}
for(i=0; i< n; i++){
if ((pid=fork()) <0 ){
printf("Error al emplear fork\n");
exit(EXIT_FAILURE);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
else if (pid ==0){// soy el hijo
yo = getpid();
padre = getppid();
printf("HIJO: %d, mi padre es: %d\n", yo, padre);
close(fd_0[1]);
close(fd_1[0]);
//TODO
nbytes = read(fd_0[0], readbuffer_h, sizeof(readbuffer_h));
sscanf(readbuffer_h, "%d,%d", &x, &y);
switch(i) {
case 0 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La suma es %d", yo,x,y,(x+y));
break;
case 1 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La resta es %d", yo,x,y,(x-y));
break;
case 2 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El producto es %d", yo,x,y,(x*y));
break;
case 3 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El cociente es %d", yo,x,y,(x/y));
break;
}
write(fd_1[1], str, strlen(str));
exit(EXIT_SUCCESS);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
else{ //soy el padre
yo = getpid();
printf("PADRE:%d\n", yo);
a = 3; b = 4;
close(fd_0[0]);
close(fd_1[1]);
sprintf(stringa,"%d,%d",a,b);
printf("Stringa padre : %s\n", stringa);
fflush(stdout);
write(fd_0[1],stringa,strlen(stringa)); // questa write non va a buon fine
wait(&status);
read(fd_1[0], readbuffer_p, sizeof(readbuffer_p));
printf("%s\n",readbuffer_p);
fflush(stdout);
}
}
close(fd_0[0]);
close(fd_0[1]);
close(fd_1[0]);
close(fd_1[1]);
return 0;
}
您尝试使用相同的管道与每个 child 进行通信,这会给自己带来麻烦。
您在程序的开头创建了两个管道。在循环的第一次迭代中,parent 分叉,child 继承所有 parent 的打开文件描述符。 child 关闭不需要的管端,parent 关闭不需要的管端 。沟通按预期进行(我想)——到目前为止一切顺利。
但现在考虑循环的第二次迭代。您再次 fork,child 再次继承了 parent 的打开文件描述符。但是现在,child 想要使用的文件描述符在循环的前一次迭代中被 parent 关闭了。我有点惊讶 child 然后在尝试使用这些文件描述符时得到 EPIPE
而不是 EBADF
,但我一点也不惊讶它的读取尝试失败。
最干净的做法是为每个 child 创建一对新管道,而不是尝试重复使用一组管道。如果你想让它只与一对一起工作,那么 parent 进程必须避免关闭任何管道末端(尽管如果你愿意,child 进程可能会关闭它们的副本)。
你好,我要开发这个程序来创建 4 children,然后依次让它们做一个简单的操作。第一个做加法,第二个做其余的,第三个做乘法,第四个做除法。父亲将他希望children到"calculate"的两个数字的字符串写在套接字上,每个children都应该读取这个字符串,提取数字并进行操作。显然,作为两个管道,需要父亲每次都写入字符串,因为在 child 中读取。我真的不明白为什么在第二次迭代时,我收到了父亲写的 SIGPIPE。有人可以向我解释为什么吗?我在调试上浪费了 3 天,但我什么也没找到。非常感谢。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
/*
fd_0 padre escribe y hijo lee ==== padre cierra fd_0[0] y hijo cierra fd_0[1]
fd_1 hijo escribe y padre lee === padre cierra fd_1[1] y hijo cierra fd_1[0]
*/
int main (int argc, char * argv[]){
char * str = malloc(100*sizeof(char));//hijo
char readbuffer_h[150];
char * stringa = malloc(100*sizeof(char));//padre
char readbuffer_p[150];
int a,b;
int x,y;
int n = 4;
int i,status,nbytes, pipe_status;
int pid, ppid,yo,padre;
int fd_0[2], fd_1[2] ;
pipe_status=pipe(fd_0);
if(pipe_status==- 1) {
perror("Error creando la tuberia 0\n");
exit(EXIT_FAILURE);
}
pipe_status=pipe(fd_1);
if(pipe_status== -1) {
perror("Error creando la tuberia 1 \n");
exit(EXIT_FAILURE);
}
for(i=0; i< n; i++){
if ((pid=fork()) <0 ){
printf("Error al emplear fork\n");
exit(EXIT_FAILURE);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
else if (pid ==0){// soy el hijo
yo = getpid();
padre = getppid();
printf("HIJO: %d, mi padre es: %d\n", yo, padre);
close(fd_0[1]);
close(fd_1[0]);
//TODO
nbytes = read(fd_0[0], readbuffer_h, sizeof(readbuffer_h));
sscanf(readbuffer_h, "%d,%d", &x, &y);
switch(i) {
case 0 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La suma es %d", yo,x,y,(x+y));
break;
case 1 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La resta es %d", yo,x,y,(x-y));
break;
case 2 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El producto es %d", yo,x,y,(x*y));
break;
case 3 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El cociente es %d", yo,x,y,(x/y));
break;
}
write(fd_1[1], str, strlen(str));
exit(EXIT_SUCCESS);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
else{ //soy el padre
yo = getpid();
printf("PADRE:%d\n", yo);
a = 3; b = 4;
close(fd_0[0]);
close(fd_1[1]);
sprintf(stringa,"%d,%d",a,b);
printf("Stringa padre : %s\n", stringa);
fflush(stdout);
write(fd_0[1],stringa,strlen(stringa)); // questa write non va a buon fine
wait(&status);
read(fd_1[0], readbuffer_p, sizeof(readbuffer_p));
printf("%s\n",readbuffer_p);
fflush(stdout);
}
}
close(fd_0[0]);
close(fd_0[1]);
close(fd_1[0]);
close(fd_1[1]);
return 0;
}
您尝试使用相同的管道与每个 child 进行通信,这会给自己带来麻烦。
您在程序的开头创建了两个管道。在循环的第一次迭代中,parent 分叉,child 继承所有 parent 的打开文件描述符。 child 关闭不需要的管端,parent 关闭不需要的管端 。沟通按预期进行(我想)——到目前为止一切顺利。
但现在考虑循环的第二次迭代。您再次 fork,child 再次继承了 parent 的打开文件描述符。但是现在,child 想要使用的文件描述符在循环的前一次迭代中被 parent 关闭了。我有点惊讶 child 然后在尝试使用这些文件描述符时得到 EPIPE
而不是 EBADF
,但我一点也不惊讶它的读取尝试失败。
最干净的做法是为每个 child 创建一对新管道,而不是尝试重复使用一组管道。如果你想让它只与一对一起工作,那么 parent 进程必须避免关闭任何管道末端(尽管如果你愿意,child 进程可能会关闭它们的副本)。