Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在shell和error.log文件中写入子级的输出_C_Pipe_Fork - Fatal编程技术网

C 在shell和error.log文件中写入子级的输出

C 在shell和error.log文件中写入子级的输出,c,pipe,fork,C,Pipe,Fork,我试图通过管道将孩子的输出传输到一个文件中,并由父亲编写 #include <stdio.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <stdbool.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys

我试图通过管道将孩子的输出传输到一个文件中,并由父亲编写

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

int prepare_log(void){
    int fd = open("error.log",
        O_CREAT | O_RDWR | O_APPEND,
        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
    return fd;
}

void log_stderr(int pipe_ends[], int outfile){
    close(pipe_ends[1]);
    dup2(pipe_ends[0],outfile);
    close(pipe_ends[0]);

}
void child(int pipe_ends[], char* argv[]){
    close(pipe_ends[0]);
    dup2(pipe_ends[1],1);
    close(pipe_ends[1]);
    execvp(argv[0], argv);
}

void bury(){
    int status;
    wait(0);

}

int main(){
    int fd = prepare_log();
    char* argv[] = {"seq", "10", NULL};

    int pipe1[2];
    if(pipe(pipe1) == -1){
        printf("Dont' create Pipe\n");
        exit(EXIT_FAILURE);
    }


    pid_t pid = fork();
    if(pid < 0){
        perror("ERROR");
        exit(EXIT_FAILURE);
    } else if(pid > 0){
        log_stderr(pipe1, fd);
        bury();
    } else if (pid == 0){
        child(pipe1,argv);
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int准备日志(无效){
int fd=open(“error.log”,
O|u CREAT | O|RDWR | O|u APPEND,
S|IRUSR | S|IWUSR | S|IWGRP | S|IWGRP | S|IROTH | S|IWOTH);
返回fd;
}
无效日志文件(内部管道末端[],内部输出文件){
关闭(管道末端[1]);
dup2(管端[0],输出文件);
关闭(管道末端[0]);
}
无效子项(int pipe_end[],char*argv[]){
关闭(管道末端[0]);
dup2(管端[1],1);
关闭(管道末端[1]);
execvp(argv[0],argv);
}
void bury(){
智力状态;
等待(0);
}
int main(){
int fd=准备日志();
char*argv[]={“seq”,“10”,NULL};
int-pipe1[2];
如果(管道(管道1)=-1){
printf(“不创建管道”);
退出(退出失败);
}
pid_t pid=fork();
if(pid<0){
佩罗(“错误”);
退出(退出失败);
}否则,如果(pid>0){
日志文件(管道1,fd);
bury();
}否则如果(pid==0){
儿童(pipe1,argv);
}
}
目前,我只尝试通过管道将child的输出传递给父亲,然后将其写入文件。 我的最终目标也是向终端显示它。我的想法是使用3个管道并重定向我们在代码中看到的第一个管道,作为第2个和第3个管道的输入。然后 用dup2(pipe2[1],文件1)重定向第二个管道的输出,用dup2(pipe2[1],标准输出)重定向第三个管道的输出。

程序设计 父进程必须从子进程读取响应,并安排将该信息写入两次,一次写入日志文件,一次写入终端。或者,您必须将子对象的输出安排到一个类似
tee
的程序,该程序将其输入的副本写入多个目的地

除非您使用一个管道将子管道的输出重定向到
tee
,否则更多管道将没有帮助

关闭管道文件描述符
子进程中没有关闭足够的文件描述符


经验法则:如果 将管道的一端连接到标准输入或标准输出,关闭两个 返回的原始文件描述符 尽快。 特别是,在使用任何 函数族

如果将描述符与 或 使用
F_DUPFD
F_DUPFD\u CLOEXEC


如果父进程不通过 在安装管道时,必须确保管道两端提前关闭 足够的(例如,在等待之前)让它的孩子可以接受 读取(或获取信号管信号或写入错误)时的EOF指示 写入),而不是无限期地阻塞。 即使父级使用管道而不使用
dup2()
,它也应该 通常情况下,至少关闭管道的一端-这是非常罕见的 在单个管道两端读写的程序

请注意,
O_CLOEXEC
选项 , 而
fcntl()
FD\u CLOEXEC
F\u DUPFD\u CLOEXEC
选项也可以考虑 我开始讨论这个问题

如果你使用 及其广泛的支持功能系列(共21项功能), 您将需要查看如何在生成的进程中关闭文件描述符 (, 等等)

请注意,使用
dup2(a,b)
比使用
close(b)更安全;dup(a)
由于种种原因。
一个是,如果要强制文件描述符的大小大于
通常的数字,
dup2()
是唯一可行的方法。 另一个是,如果
a
b
相同(例如,两者都
0
),则
dup2()
正确处理它(在复制
a
之前,它不会关闭
b
) 而单独的
close()
dup()
却失败得很厉害。 这不太可能,但并非不可能

充分固定码 这是您的程序的固定版本。
log\u stderr()
中的逻辑是奇数;它不做的一件事是写入标准错误。我对它进行了修改,这样它就可以从管道中读取并写入标准输出和日志文件。请注意,复制信息需要一次读取,但需要两次写入。错误检查很简单,几乎不存在。
bury()
函数现在报告儿童死亡。代码保存在
pipe71.c
中,并编译为
pipe71

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

static
int prepare_log(void)
{
    int fd = open("error.log",
                  O_CREAT | O_RDWR | O_APPEND,
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
    return fd;
}

static
void log_stderr(int pipe_ends[], int outfile)
{
    char buffer[512];
    int nbytes;
    close(pipe_ends[1]);
    while ((nbytes = read(pipe_ends[0], buffer, sizeof(buffer))) > 0)
    {
        write(STDOUT_FILENO, buffer, nbytes);
        write(outfile, buffer, nbytes);
    }
    close(pipe_ends[0]);
    close(outfile);
}

static
void child(int pipe_ends[], char *argv[])
{
    dup2(pipe_ends[1], 1);
    close(pipe_ends[0]);
    close(pipe_ends[1]);
    execvp(argv[0], argv);
    fprintf(stderr, "failed to execute %s\n", argv[0]);
    exit(EXIT_FAILURE);
}

static
void bury(void)
{
    int status;
    int corpse;
    while ((corpse = wait(&status)) > 0)
        printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
}

int main(void)
{
    int fd = prepare_log();
    char *argv[] = {"seq", "10", NULL};

    int pipe1[2];
    pipe(pipe1);

    pid_t pid = fork();

    if (pid > 0)
    {
        log_stderr(pipe1, fd);
        bury();
    }
    else if (pid == 0)
    {
        child(pipe1, argv);
    }
    return 0;
}

您没有在子项中关闭足够的文件描述符。经验法则:如果将管道的一端连接到标准输入或标准输出,请尽快从
pipe()
关闭两个原始文件描述符。特别是,这意味着在使用任何函数族之前。该规则也适用于
dup()
F_DUPFD
。进程是无性别的。s/father/parent/这是否意味着我应该关闭管道的两端bevor runn the exec in child,但只关闭父管道的write and,这样他仍然可以读取?是的,这确实意味着您需要同时关闭
(pipe_ends[0])
关闭(管道末端[1])
execv()之前
。通常,如果不关闭所有未使用的描述符,则在检测EOF时可能会遇到问题。在这种情况下,您可能还可以;你可能不会。但是草率的编码使得调试程序为什么挂起变得很困难,这是管道关闭不当的常见症状。将管道的读取端连接到指定为
outfile
的文件描述符似乎很奇怪。这将导致混淆,部分原因是这并不意味着写入管道的信息将自动写入输出文件,部分原因是仅对
输出文件执行读取操作<
$ rm error.log
$ ./pipe71
1
2
3
4
5
6
7
8
9
10
99989: child 99990 exited with status 0x0000
$ cat error.log
1
2
3
4
5
6
7
8
9
10
$