进程之间的管道链
我想要一个父母带着两个孩子。
父进程从文件“a.txt”中读取数据并将管道发送给第一个子进程;第一个孩子读取字符并将小写字母发送给第二个孩子。
第二个子级在“b.txt”中打印每个不同的字符和出现次数(每行),然后通过管道将不同字符的数量发送到父级。父级打印第二个子级的结果。
我已经完成了从父级到 1 个子级的管道,并且为了测试我已将管道放回父级。 我不明白的是如何让管道传给第二个孩子。我一直在搜索有关 dup2 的信息,但我不知道如何使其工作。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
void main()
{
int pfd1[2], pfd2[2], pid1, pid2, pfin, status, fd;
char *c = (char *)malloc(sizeof(char));
if (pipe(pfd1) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if (pipe(pfd2) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if ((pid1 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid1 == 0) { /*child */
close(pfd1[1]);
while (read(pfd1[0], c, 1) > 0) {
//printf("%s",c);
if (islower(*c)) {
close(pfd2[0]);
//inchid capul de citire; scriu in pipe
write(pfd2[1], c, 1);
////dup??????
}
}
printf("\n");
write(pfd[1], buff, len);
close(pfd1[0]);
close(pfd2[1]);
exit(0);
}
if ((pid2 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid2 == 0) {
printf("second child");
exit(0);
}
/* parent */
close(pfd1[0]);
close(pfd2[1]);
fd = open("date.txt", O_RDONLY);
while (read(fd, c, 1) > 0) {
write(pfd1[1], c, 1);
}
close(pfd1[1]); /* la sfarsit inchide si capatul utilizat */
close(pfin);
while (read(pfd2[0], c, 1) > 0)
printf("%s", c);
close(pfd2[0]);
printf("%d", wait(&status));
printf("%d", wait(&status));
}
I want to have one parent with 2 children.
The parent reads from file "a.txt" and sends trough pipe to first child; the first child reads the chars and sends to the second child the lower letter chars.
The second child prints in "b.txt" each distinct char and number of appearances(per line) and then sends trough a pipe to the parent the number of distinct chars. The parent prints the result from the second child.
I've done the pipe from parent to 1 child and to test I've put a pipe back to the parent.
What I can't figure it out is how to make the pipe go to the second child. I've been searching for information on dup2
but I don't get on how to make it work.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
void main()
{
int pfd1[2], pfd2[2], pid1, pid2, pfin, status, fd;
char *c = (char *)malloc(sizeof(char));
if (pipe(pfd1) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if (pipe(pfd2) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if ((pid1 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid1 == 0) { /*child */
close(pfd1[1]);
while (read(pfd1[0], c, 1) > 0) {
//printf("%s",c);
if (islower(*c)) {
close(pfd2[0]);
//inchid capul de citire; scriu in pipe
write(pfd2[1], c, 1);
////dup??????
}
}
printf("\n");
write(pfd[1], buff, len);
close(pfd1[0]);
close(pfd2[1]);
exit(0);
}
if ((pid2 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid2 == 0) {
printf("second child");
exit(0);
}
/* parent */
close(pfd1[0]);
close(pfd2[1]);
fd = open("date.txt", O_RDONLY);
while (read(fd, c, 1) > 0) {
write(pfd1[1], c, 1);
}
close(pfd1[1]); /* la sfarsit inchide si capatul utilizat */
close(pfin);
while (read(pfd2[0], c, 1) > 0)
printf("%s", c);
close(pfd2[0]);
printf("%d", wait(&status));
printf("%d", wait(&status));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我对您的代码有一些具体的评论:
虽然这没有任何问题,但也不需要从堆中分配这个
char
。更惯用的方法是在此处使用char c;
,然后将&c
传递给read(2)
和write(2)系统调用。 (更惯用的做法是使用 C 标准 IO 工具;
freopen(3)
、getchar(3)
和putchar(3)
-- 但是,在您让此代码完全按照您希望的方式工作之前,不要进行这种转换,因为这对您试图解决的问题来说是一个额外的复杂化。)通过使用您自己的错误消息,您会错过重要的错误信息。您应该使用
perror(3)
来打印错误消息。这将为您和您的用户提供可以搜索的错误的实际原因。如果您的用户遇到setrlimit(2)
NPROC
最大进程限制、系统范围的进程限制,fork(2)
可能会失败,内核内存不足。您还应该检查
open(2)
调用的返回值。 (您应该还检查write(2)
和close(2)
的返回值是否有错误,但处理这些错误是对于大多数程序来说,简单地打印错误并退出是一个好的开始。)这是
close(2)
调用的错误位置 - 您不应该一遍又一遍地关闭此文件描述符。每个输入字符。如果您检查close(2)
返回值,您会注意到errno
设置为EBADF
,因为文件描述符不再有效第二次及后续调用。现在,讨论您来这里的问题:将挂钩的
fork()
、pipe()
和dup2()
调用的序列启动管道中的所有进程并将数据发送回父进程。由于pipe(2)
创建单向pipe(7)
,因此您需要调用pipe(2)
四次< /em> -- 用于父级和子级之间的双向。如果您将管道端点存储在具有对您有意义的名称的数组中,那么它们将更容易跟踪。也许创建名为to_
的数组用于写入,from_
用于读取:请注意,您实际上需要使用
dup2( 2)
重新排列文件描述符,除非您想要执行其他程序来处理“过滤”任务。只需使用from_parent[...]
或from_child[...]
描述符进行read(2)
和write(2)
到to_child[...]
和to_parent[...]
描述符。也许使用
socketpair(2)
使用AF_UNIX
创建双向套接字,然后可以读取和写入,整个事情会更容易以与任何其他 BSD 风格套接字相同的方式。请参阅socket(7)
和unix(7)
了解概述。I have a few specific comments on your code:
While there is nothing wrong with this, there is also no need for this
char
to be allocated from the heap. The more idiomatic approach would usechar c;
here and then pass&c
toread(2)
andwrite(2)
system calls. (Even more idiomatic would be to use the C Standard IO facility;freopen(3)
,getchar(3)
, andputchar(3)
-- but do not make that transition until you have this code working exactly as you want it to, because it is an additional complication with the problem you're trying to solve.)By using your own error message, you are missing out on important error information. You should use
perror(3)
to print an error message instead. This will give you and your users an actual cause for errors that they can search for.fork(2)
can fail if your user is running into thesetrlimit(2)
NPROC
maximum process limit, the system-wide process limit, out of kernel memory.You should also check the return value from
open(2)
calls. (You're supposed to also check the return values fromwrite(2)
andclose(2)
for errors, but handling these errors is harder. Simply printing the error and quitting is a good start for most programs.)This is the wrong location for the
close(2)
call -- you shouldn't be closing this filedescriptor over and over for every input character. If you were checking theclose(2)
return value, you would noticeerrno
is set toEBADF
because the file descriptor is no longer valid on the second and subsequent calls.Now, onto the problem you came here for: the sequence of
fork()
,pipe()
, anddup2()
calls that will hook up all your processes in a pipeline and send data back to the parent process. Sincepipe(2)
creates uni-directionalpipe(7)
s, you need to callpipe(2)
four times -- for both directions between parent and children. If you store the pipe endpoints in arrays with names that mean something to you, they will be easier to keep track of. Perhaps create arrays namedto_
for writing into andfrom_
for reading from:Note that you don't actually need to use
dup2(2)
to re-arrange the filedescriptors unless you want to execute other programs to handle the "filter" task. Justread(2)
using thefrom_parent[...]
orfrom_child[...]
descriptors andwrite(2)
to theto_child[...]
andto_parent[...]
descriptors.Maybe the entire thing would be easier with
socketpair(2)
usingAF_UNIX
to create bi-directional sockets, which can then be read from and written to in the same fashion as any other BSD-style socket. Seesocket(7)
andunix(7)
for an overview.您不需要
dup()
。只需打开父级中的管道,然后在每个进程中close()
您不需要的端点,然后仅使用您需要的端点。请注意,这意味着父级将关闭子级通信管道的两个端点。该管道的每个端点都将由子管道之一使用。每个孩子还应该关闭它不使用的端点。
You do not need
dup()
. Simply open the pipes in the parent and then in each processclose()
the endpoints you don't need and just use the endpoints you do need.Note that this means that the parent will close both endpoints of the pipe for child-child communication. Each of the endpoints of this pipe will be used by one of the children. Each child should also close the endpoint it doesn't use.
谢谢您的回答。
这是整个问题的代码。
Thank you for your answers.
Here is the code for the whole problem.