所以我试图理解管道在UNIX中是如何工作的,我试图将文本管道排序,对它们进行排序并将它们管道传回main to doo。但是当执行到达时:
注意:程序将文本文件作为参数。
execlp("sort", "sort",(char *)0);
程序停止并保持静止,就像从管道中等待一样。我知道我必须了解UNIX管道。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid;
FILE *fdin;
long fsize;
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid = fork()) == -1){
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid != 0){
char buf[1024];
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
fread(buf, sizeof(buf), 1, fdin);
fclose(fdin);
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
}
else if (childpid == 0){
char buf[1024];
close(pipe1[1]);
close(pipe2[0]);
//dup2(pipe2[1], STDOUT_FILENO);
//dup2(pipe1[0], STDIN_FILENO);
read(pipe1[0], buf, sizeof(buf));
close(pipe1[0]);
printf("%s\n\n", buf);
dup2(pipe2[1], STDOUT_FILENO);
close(pipe2[1]);
execlp("sort", "sort",(char *)0);
printf("%s\n", buf);
exit(0);
}
// wait child
wait(NULL);
// parent read pipe 2 and print
if (childpid != 0){
// DOOOO
//read(pipe2[0], buf, 1024);
//printf("%s\n", buf);
}
return 0;
}
更新:1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
//char *message = "This is a message!!!";
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid[2];
FILE *fdin;
char buf[1024];
//long fsize;
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid[0] = fork()) == -1)
{
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid[0] != 0){
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
fread(buf, sizeof(buf), 1, fdin);
fclose(fdin);
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
}
else if (childpid[0] == 0){
buf[0] = '\0';
int pipe3[2];
pipe(pipe3);
close(pipe1[1]);
close(pipe2[0]);
//dup2(pipe2[1], STDOUT_FILENO);
dup2(pipe1[0], STDIN_FILENO);
//dup2(pipe3[1],STDOUT_FILENO);
read(pipe1[0], buf, sizeof(buf));
close(pipe1[0]);
write(pipe3[1], buf, sizeof(buf));
printf("-PIPED BUFF-\n%s\n\n", buf);
if ((childpid[1] = fork()) == -1){
perror("fork second child");
exit(1);
}
// Child of child (sort call)
if (childpid[1] != 0){
close(pipe2[1]);
close(pipe3[0]);
printf("I AM YOUR FATHER LOOK\n");
}else{
printf("a\n");
buf[0] = '\0';
printf("b\n");
close(pipe3[1]);
printf("c\n\n");
dup2(pipe3[0], STDIN_FILENO);
read(pipe3[0], buf, sizeof(buf));
close(pipe3[0]);
printf("-SORT BUFF-\n%s\n\n", buf);
//dup2(pipe2[1], STDOUT_FILENO);
close(pipe2[1]);
execlp("sort","sort",(char *)0);
printf("-SORTED BUFF-\n%s\n\n", buf);
exit(0);
}
// wait second child exec
wait(NULL);
//printf("%s\n", buf);
exit(0);
}
// wait child exec
//wait(NULL);
int status;
pid_t pid;
int n = 2;
while (n > 0){
pid = wait(&status);
printf("-SORTED BUFF-\n%s\n\n", buf);
--n;
}
// parent read pipe 2 and print
if (childpid[0] != 0){
printf("asd\n");
buf[0] = '\0';
dup2(pipe2[0], STDIN_FILENO);
read(pipe2[0], buf, sizeof(buf));
close(pipe2[0]);
printf("-SORTED BUFF-\n%s\n\n", buf);
}
return 0;
}
答案 0 :(得分:1)
目的是让父文件打开文件并将其写入管道。在同一时间,我们有一个孩子,创建第二个管道并阅读它。而且在同一时间,我们又有了第二个孩子。
我们需要2个孩子和2个管道。第一个父母等待第一个孩子,第一个孩子等待第二个孩子。
我不知道它是否完美,因为我无法测试,这件事情之王非常复杂:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
static int wait_and_return(pid_t pid) {
int status;
if (waitpid(pid, &status, 0) == -1) {
perror("waitpid()");
return 1;
}
return status;
}
static pid_t create_pipe_and_fork(int fd_pipe[2]) {
if (pipe(fd_pipe) == -1) {
perror("pipe()");
return -1;
}
pid_t pid = fork();
if (pid == -1) {
close(fd_pipe[0]);
close(fd_pipe[1]);
perror("fork()");
return -1;
}
return pid;
}
static int exec_sort(int fd_in, int fd_out) {
if (dup2(fd_in, STDIN_FILENO) == -1 || dup2(fd_out, STDOUT_FILENO) == -1) {
close(fd_in);
close(fd_out);
perror("dup2()");
return 1;
}
close(fd_in);
close(fd_out);
execlp("sort", "sort", (char *)NULL);
perror("execlp()");
return 1;
}
static int child(int fd) {
int fd_pipe[2];
pid_t pid = create_pipe_and_fork(fd_pipe);
if (pid == -1) {
close(fd);
return 1;
}
if (pid != 0) {
close(fd);
close(fd_pipe[1]);
char buf[4048];
ssize_t ret;
while ((ret = read(fd_pipe[0], buf, sizeof buf)) > 0) {
if (ret > INT_MAX) {
close(fd_pipe[0]);
wait_and_return(pid);
return 1;
}
printf("%.*s", (int)ret, buf);
}
close(fd_pipe[0]);
return wait_and_return(pid);
} else {
close(fd_pipe[0]);
return exec_sort(fd, fd_pipe[1]);
}
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "wrong argument\n");
return 1;
}
int fd_pipe[2];
pid_t pid = create_pipe_and_fork(fd_pipe);
if (pid == -1) {
return 1;
}
if (pid != 0) {
close(fd_pipe[0]);
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("fopen():");
close(fd_pipe[1]);
wait_and_return(pid);
return 1;
}
char buf[4048];
size_t ret;
while ((ret = fread(buf, sizeof *buf, sizeof buf / sizeof *buf, file))) {
write(fd_pipe[1], buf, ret);
}
fclose(file);
close(fd_pipe[1]);
return wait_and_return(pid);
} else {
close(fd_pipe[1]);
return child(fd_pipe[0]);
}
}
可以反转主要和最后一个孩子的角色,因此主要读取结果,孩子将打开文件。我让你试试。
答案 1 :(得分:1)
在您的父代码中,您有:
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
这在多个方面存在问题:
sort
的结果写入其原始标准输出。close(pipe1[1])
时,管道仍然有一个打开的文件描述符(父级的标准输出),因此sort
永远不会在管道上获得EOF
。< / LI>
由于孩子要wait()
完成,但孩子不知道其输入是否完整,否则就会出现死锁。然后,您可以使用代码来读取输入数据,但由于dup2()
而无法清除您要写入的位置。
dup2()
。原则上,整个设计只能起作用,因为sort
在写入任何输出之前必须读取所有输入。如果您有一个awk
或sed
之类的命令可以在完成读取输入之前编写输出,那么您的双向管道方案在大量数据上将无法正常工作。当父级仍在尝试写入并发现其管道缓冲区已满时,子级可能会填充管道缓冲区(并且无法再向其写入)。两个进程都会陷入写入,等待另一个进行读取。有很多方法 - select()
,poll()
,多个主题等等 - 但它们超出了您想要或现在需要处理的范围。
此外,您的程序将输入限制为sort
至最多1024个字节。这还不足以填充任何管道缓冲区,这意味着除非执行的命令增加了它必须写回的数据量与读入的数据相比 - 例如,如果您将URL发送到获取来自这些网址的数据 - 然后您就不会遇到死锁。
子代码似乎从管道中读取数据,然后启动sort
(但sort
没有任何内容可供阅读),并且似乎期待execlp()
回来。代码只需要将管道的正确末端连接到标准输入和输出,关闭所有管道文件描述符,然后执行sort
。如果execlp()
返回,则失败 - 报告错误。
sort
进行阅读和写作。留下了许多评论的位。添加了关键错误检查。例如,在执行任何其他操作之前,请检查命令行是否正确。通常,您在分叉前打开文件;这一次,最好不要这样做。报告标准错误的错误。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid;
FILE *fdin;
if (argc != 2)
{
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid = fork()) == -1){
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid != 0){
//long fsize;
char buf[1024];
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
if (fdin == 0)
{
fprintf(stderr, "%s: failed to open file '%s'\n", argv[0], argv[1]);
exit(1);
}
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
int nbytes = fread(buf, 1, sizeof(buf), fdin);
if (nbytes <= 0)
{
fprintf(stderr, "%s: no data in file '%s'\n", argv[0], argv[1]);
exit(1);
}
fclose(fdin);
//dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, nbytes);
close(pipe1[1]);
}
else if (childpid == 0){
//char buf[1024];
close(pipe1[1]);
close(pipe2[0]);
dup2(pipe2[1], STDOUT_FILENO);
dup2(pipe1[0], STDIN_FILENO);
close(pipe2[1]);
close(pipe1[0]);
//read(pipe1[0], buf, sizeof(buf));
//close(pipe1[0]);
//printf("%s\n\n", buf);
//dup2(pipe2[1], STDOUT_FILENO);
//close(pipe2[1]);
execlp("sort", "sort",(char *)0);
fprintf(stderr, "%s: failed to exec 'sort'\n", argv[0]);
exit(1);
}
// wait child
wait(NULL);
// parent read pipe 2 and print
if (childpid != 0){
char buf[1024];
int nbytes;
while ((nbytes = read(pipe2[0], buf, sizeof(buf))) > 0)
printf("%.*s", nbytes, buf);
}
return 0;
}
请注意在两次读取操作中仔细捕获大小。
考虑输入文件:
Harlequin
Preposterous
Animagus
Zealot
Queensbury Rules
Quaternion
Hedwig
Tensor
Tenser
我得到的输出是:
Animagus
Harlequin
Hedwig
Preposterous
Quaternion
Queensbury Rules
Tenser
Tensor
Zealot
这对我来说是正确的。