Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.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
在unixc中使用管道_C_Linux_Unix_Pipe - Fatal编程技术网

在unixc中使用管道

在unixc中使用管道,c,linux,unix,pipe,C,Linux,Unix,Pipe,我在使用C语言中的管道时遇到了严重的问题。我应该从命令行(例如:./myprogram 123 45 67)接收参数,将参数一次读取一个字符到缓冲区,将字符发送到要计数的子进程,然后返回读取到父进程的字符总数。我的代码如下(注意:注释是我应该做的): //命令行参数中的字符被发送到子进程 //从父进程通过管道一次一个。 //子进程统计通过管道发送的字符数。 //子进程返回计数给父进程的字符数。 //父进程打印子进程计数的字符数。 #包括 #包括 #包括 #包括 #包括 静态int-toChild

我在使用C语言中的管道时遇到了严重的问题。我应该从命令行(例如:./myprogram 123 45 67)接收参数,将参数一次读取一个字符到缓冲区,将字符发送到要计数的子进程,然后返回读取到父进程的字符总数。我的代码如下(注意:注释是我应该做的):

//命令行参数中的字符被发送到子进程
//从父进程通过管道一次一个。
//子进程统计通过管道发送的字符数。
//子进程返回计数给父进程的字符数。
//父进程打印子进程计数的字符数。
#包括
#包括
#包括
#包括
#包括
静态int-toChild[2];
静态int-fromChild[2];
静态字符缓冲区;
int main(int argc,字符**argv)
{
智力状态;
int-nChars=0;
pid_t pid;
管道(toChild);
管道(来自儿童);
如果((pid=fork())=-1){
printf(“分叉错误%d\n”,pid);
返回-1;
}
否则如果(pid==0){
关闭(toChild[1]);
关闭(fromChild[0]);
//通过管道从父进程接收字符
//一次一个,数一数。
整数计数=0;
printf(“即将阅读的孩子”);
while(读取(toChild[0],&buffer,1)){
计数++;
}
//返回计数到父进程的字符数。
写入(fromChild[1],&count,sizeof(count));
关闭(toChild[0]);
关闭(fromChild[1]);
printf(“子退出\n”);
}
否则{
关闭(toChild[0]);
关闭(fromChild[1]);
//--在父进程中运行--
printf(“CS201-作业3-Chris Gavette\n”);
写入(toChild[1],&argv[1],1);
//从以开头的命令行参数发送字符
//argv[1]通过管道到子进程一次一个。
读取(从子项[0],&nChars,1);
//等待子进程返回。获取子进程。
//接收通过值计数的字符数
//在收获子进程时返回。
关闭(toChild[1]);
关闭(fromChild[0]);
waitpid(pid和status,0);
printf(“子计数的%d个字符\n”,nChars);
printf(“父出口”);
返回0;
}
}

即使我关闭了两个管道的两端,子进程似乎仍挂起。

首先,这是错误的

write(toChild[1], &count, 1) 
它最终会导致你的问题
count
是一个
int
,而不是
char
unsigned char
。您需要发送
sizeof(count)
。此外,遇到错误时,read函数将返回EOF(非零),因此您的子退出条件不合适。它应该是这样的:

while(read(toChild[0], &buffer, 1) == 1)
最后,您的父进程应该循环遍历
argv[]
中的每个参数,并将每个参数作为
strlen
大小的缓冲区发送

我几乎可以肯定这就是你想要做的。请注意,为了在了解哪个描述符用于特定目的时保持清醒,我更喜欢使用
#define
来记录每个进程用于读写的内容。这可以扩展到任意数量的进程,顺便说一句,我相信这对于您的下一个任务来说不会太远:

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

// P0_READ   - parent read source
// P0_WRITE  - parent write target
// P1_READ   - child read source
// P1_WRITE  - child write target

#define P0_READ     0
#define P1_WRITE    1
#define P1_READ     2
#define P0_WRITE    3
#define N_PIPES     4

int main(int argc, char **argv)
{
    int fd[N_PIPES], count = 0, i;
    pid_t pid;
    char c;

    if (pipe(fd) || pipe(fd+2))
    {
        perror("Failed to open pipe(s)");
        return EXIT_FAILURE;
    }

    // fork child process
    if ((pid = fork()) == -1)
    {
        perror("Failed to fork child process");
        return EXIT_FAILURE;
    }

    // child process
    if (pid == 0)
    {
        // close non P1 descriptors
        close(fd[P0_READ]);
        close(fd[P0_WRITE]);

        // get chars from input pipe, counting each one.
        while(read(fd[P1_READ], &c, 1) == 1)
            count++;

        printf("Child: count = %d\n", count);
        write(fd[P1_WRITE], &count, sizeof(count));

        // close remaining descriptors
        close(fd[P1_READ]);
        close(fd[P1_WRITE]);
        return EXIT_SUCCESS;
    }

    // parent process. start by closing unused descriptors
    close(fd[P1_READ]);
    close(fd[P1_WRITE]);

    // send each arg
    for (i=1; i<argc; ++i)
        write(fd[P0_WRITE], argv[i], strlen(argv[i]));

    // finished sending args
    close(fd[P0_WRITE]);

    // Wait for child process to return.
    wait(NULL);

    // wait for total count
    if (read(fd[P0_READ], &count, sizeof(count)) == sizeof(count))
        printf("Parent: count = %d\n", count);

    // close last descriptor
    close(fd[P0_READ]);

    return 0;
}
输出

./progname argOne argTwo
Child: count = 12
Parent: count = 12

编辑:具有子返回状态的单管道

从原始问题的注释来看,您的作业可能要求获取子进程的返回状态作为结果计数,而不是在管道中返回。在执行此操作时,可以使用单个管道描述符对执行此操作。我更喜欢第一种方法,但这同样有效:

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

// P0_WRITE  - parent write target
// P1_READ   - child read source

#define P1_READ     0
#define P0_WRITE    1
#define N_PIPES     2

int main(int argc, char **argv)
{
    int fd[N_PIPES], count = 0;
    pid_t pid;
    char c;

    if (pipe(fd))
    {
        perror("Failed to open pipe(s)");
        return EXIT_FAILURE;
    }

    // fork child process
    pid = fork();
    if (pid == -1)
    {
        perror("Failed to fork child process");
        return EXIT_FAILURE;
    }

    if (pid == 0)
    {
        // close non P1 descriptors
        close(fd[P0_WRITE]);

        // Return number of characters counted to parent process.
        while(read(fd[P1_READ], &c, 1) == 1)
            ++count;

        close(fd[P1_READ]);
        printf("Child: count = %d\n", count);
        return count;
    }

    // parent process. start by closing unused descriptors
    close(fd[P1_READ]);

    // eacn each arg entirely
    for (int i=1; i<argc; ++i)
        write(fd[P0_WRITE], argv[i], strlen(argv[i]));

    // finished sending args
    close(fd[P0_WRITE]);

    // Wait for child process to return.
    if (wait(&count) == -1)
    {
        perror("Failed to wait for child process");
        return EXIT_FAILURE;
    }

    printf("Parent: count = %d\n", WEXITSTATUS(count));

    return 0;
}
从命令行运行时,将提供:

Child: count = 12
Parent: count = 12

我喜欢双管道方法的众多原因之一。

在此过程中有两个
fork
调用。你知道的,对吧?第二种方法会盲目覆盖第一种方法返回的pid。拿出第一个。然后考虑你正在执行的所有读/写调用,问问你自己来回发送的东西有多大。例如:
write(toChild[1],&count,1)
。嗯,
count
int
;为什么只发送一个字节而不发送大小(计数)?您的子循环退出条件充其量是不确定的。最后,以防你没有意识到;您应该为此使用两个管道描述符对;一个也没有。啊哈,谢谢你。这解决了两次调用的问题。在我发布这个问题一两分钟后,我发现我需要两个文件描述符。我觉得自己很笨,这本应该是显而易见的。谢谢哇,非常感谢!这正是我编程输出所需要的。挂起的问题一定是由于我对读/写功能的误解造成的。我真的很感激@用户3698112很高兴它有帮助。请尝试使用宏或某种形式的符号常量将索引转换为管道描述符对/数组,至少在获得它们的句柄之前是这样。它最终将使它们更易于阅读,更不用说针对它们编写代码了。此答案张贴代码中的意图应该更直观地使用这些符号,而不是
[1]
[3]
等。祝您好运。我感谢您对可读代码的建议。这是我最近一直在努力做的事情,大多数时候,我认为我做得相当好,但这项作业给了我太多的麻烦,我几乎不加修改就把它变成了一个问题。无论如何,我真的很感谢你的帮助,我会尽力把你的建议牢记在心@user3698112还添加了单管版本,我认为这可能是您的任务目标之一。它有警告,所以请阅读张贴的评论。很高兴能提供帮助。在看2管道示例时,我认为它不适用于从子对象返回值。因为皮普
Failed to wait for child process: Interrupted system call
Child: count = 12
Parent: count = 12