我试图证明我的一个疑问,即两个不相关的进程可以共享fd
半双工管道并进行通信。
我为此创建了两个程序。但后来我又提出了另一个问题,即如果进程死了会发生什么事情?因为我的读者得到了一些垃圾信息,当我打印出信息时。
作家
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd[2];
char str[] = "hello\n";
if(pipe(fd) < 0)
perror("Pipe creation failed\n");
//Since i am a writer, i should close the reading end as a best practice
close(fd[0]);
/*
The processes need not to be related processes, in order to use the half duplex pipes. fd is just a number/identifier
which can be shared across different processes
*/
printf("Hey there !!! use this file descriptor for reading : %d\n", fd[0]);
//writing message
write(fd[1],str,strlen(str)+1);
return 0;
}
阅读器
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd,bytesRead;
char buffer[1024];
printf("please enter the fd :");
scanf("%d",&fd);
bytesRead = read(fd,buffer,1024);
printf("Bytes Read : %d\nMessage : %s\n", bytesRead, buffer);
return 0;
}
答案 0 :(得分:1)
你不能这样做。
文件描述符表是按进程的;每个进程都有自己独立的一组打开文件描述符(注意打开文件描述符,每个进程和打开文件描述之间的区别,它们是系统范围的,在open(2)
中讨论过。如果要在进程之间共享文件描述符,则需要通过fork(2)
继承文件描述符,或者通过unix(7)
通过sendmesg(2)
通过SCM_RIGHTS
传递给cmesg(3)
域套接字。 https://github.com/appsquickly/Typhoon/pull/503标题。
(在Linux上,你也可以将路径传递给/proc/[PID]/fd/...
,而其他系统可能有自己的非便携式等价物。)
在你的情况下发生的事情是读取失败(你给它一个未打开的文件描述符),留下你的缓冲区未初始化的垃圾。由于您没有检查返回值,因此您永远不会知道它失败了。
答案 1 :(得分:0)
在管道手册页中,
pipe()创建一个管道,一个可用于进程间通信的单向数据通道。数组pipefd用于返回引用管道末端的两个文件描述符。 pipefd [0]指的是管道的读取端。 pipefd [1]指的是管道的写端。写入管道写端的数据由内核缓冲,直到从管道的读端读取。
管道主要用于相关过程(父和子)。您无法将管道用于非相关流程。
在相关过程中,一端关闭。在另一端,进程获取SIGPIPE信号。
使用管道的示例程序: -
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
上面的程序创建一个管道,然后fork(2)来创建一个子进程;子进程继承了一组引用同一管道的重复文件描述符。在fork(2)之后,每个进程都会关闭管道不需要的描述符(参见管道(7))。然后父进程将程序命令行参数中包含的字符串写入管道,子进程一次从管道读取该字符串,并在标准输出上回显它。