在 fork 后使用读/写管道 2 字符串

Posted

技术标签:

【中文标题】在 fork 后使用读/写管道 2 字符串【英文标题】:Pipe 2 string using read/write after fork 【发布时间】:2022-01-03 03:51:35 【问题描述】:

我很难理解在线课程中管道和叉子如何协同工作。首先,我想在 printf 和 when all read/write end cat 两个字符串合为一个的下方键入两个字符串。 我被困在两个孩子的读/写中,问题是它与我想要的不匹配,因为首先打印字符串然后打开通道输入。也许这是一件小事,但我开始将 C 用于在线课程。读写功能是强制性的。

String 1: 
sdfsdfsdf
String 2: 
Sdfsdfdsfsdfsd
String cat:
sdfsdfsdfSdfsdfdsfsdfsd

这是我目前的代码。

int main()

    int fd1[2],fd2[2];
    int status, pid;
    pipe(fd1);
    printf("String 1: \n");
    pid = fork();
    if(pid == 0)              /* child 1*/
    
        close(fd1[0]);
        char cad1[100];
        read(0,&cad1,100);
        write(fd1[1],&cad1, 100);
        close(fd1[1]);
        exit(0);
    
    else                          /* father*/
    
        close(fd1[1]);
        printf("String 2: \n");
        pipe(fd2);
        pid = fork();
        if(pid == 0)               /* child 2 */
        
            close(fd2[0]);
            close(fd1[0]);
            char cad2[100];
            read(0,&cad2,100);
            write(fd2[1],&cad2, 100);
            close(fd2[1]);
            exit(0);
        
    
    close(fd2[0]);
    /* wait every child */
    wait(&status);
    wait(&status);
    return 0;

我的输出是这样的:

String 1: 
String 2: 
cvbcvbcvbcvb
cvbcvbcvbcvb

to cat 我的代码(未在我认为在 cat 之前调用两个管道到 char [] 变量的代码中实现。

任何改进我的代码的建议。 提前致谢。

【问题讨论】:

父代码需要从两个管道中读取来收集子节点的数据,然后将它们连接起来。您需要注意读取了多少字节,以免写入的字节数超过读取的字节数。第二个孩子应该关闭fd1[0]fd1[1],因为它不会使用它们。您需要担心换行符和空字节——read() 返回的信息不是字符串,而是包含换行符。 【参考方案1】:

这是我的代码,大致基于您的代码。正如我在comment 中所说,父代码需要从两个管道中读取以从子管道中收集数据,然后将它们连接起来。您需要注意读取了多少字节,以免写入的字节数超过读取的字节数。第二个孩子应该关闭fd1[0]fd1[1],因为它不会使用它们。您需要担心换行符和空字节——read() 返回的信息不是字符串,而是包含换行符。

我选择使用fgets() 从标准输入中读取,因为它确实返回了一个字符串并删除了换行符。我也将一些信息写入标准输出。连接的字符串是使用snprintf() 创建的。

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

static inline void syserr_exit(const char *fmt, ...)

    va_list args;
    int errnum = errno;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
    exit(EXIT_FAILURE);


int main(void)

    int fd1[2], fd2[2];
    int pid1, pid2;

    if (pipe(fd1) < 0 || pipe(fd2) < 0)
        syserr_exit("Failed to create two pipes: ");
    else if ((pid1 = fork()) < 0)
        syserr_exit("Failed to fork() child 1: ");
    else if (pid1 == 0)
    
        /* Child 1*/
        close(fd1[0]);
        close(fd2[0]);
        close(fd2[1]);
        char cad1[100];
        printf("String 1: \n");
        fflush(stdout);
        if (fgets(cad1, sizeof(cad1), stdin) == NULL)
            syserr_exit("child 1 - failed to read from standard input: ");
        cad1[strcspn(cad1, "\r\n")] = '\0';
        write(fd1[1], cad1, strlen(cad1));
        /* Should error check the write! */
        printf("child 1 wrote [%s] to the parent process\n", cad1);
        close(fd1[1]);
        exit(0);
    
    else if ((pid2 = fork()) < 0)
        syserr_exit("Failed to fork child 2: ");
    else if (pid2 == 0)
    
        /* Child 1*/
        close(fd1[0]);
        close(fd1[1]);
        close(fd2[0]);
        printf("String 2: \n");
        fflush(stdout);
        char cad2[100];
        if (fgets(cad2, sizeof(cad2), stdin) == NULL)
            syserr_exit("child 2 - failed to read from standard input: ");
        cad2[strcspn(cad2, "\r\n")] = '\0';
        write(fd2[1], cad2, strlen(cad2));
        /* Should error check the write! */
        printf("child 2 wrote [%s] to the parent process\n", cad2);
        close(fd2[1]);
        exit(0);
    
    else
    
        /* Parent */
        char buffer1[100];
        char buffer2[100];
        close(fd2[1]);
        close(fd1[1]);
        ssize_t sz1 = read(fd1[0], buffer1, sizeof(buffer1));
        buffer1[sz1] = '\0';
        close(fd1[0]);
        ssize_t sz2 = read(fd2[0], buffer2, sizeof(buffer2));
        buffer2[sz2] = '\0';
        close(fd2[0]);

        size_t tlen = sz1 + sz2 + sizeof("[]+[]");
        char concat[tlen];
        snprintf(concat, sizeof(concat), "[%s]+[%s]", buffer1, buffer2);

        /* wait for both children */
        int s1, s2;
        int c1 = wait(&s1);
        int c2 = wait(&s2);

        printf("The one child (%d) exited with status 0x%.4X\n", c1, s1);
        printf("T'other child (%d) exited with status 0x%.4X\n", c2, s2);
        printf("Received from %d (%zu bytes) [[%s]]\n", pid1, sz1, buffer1);
        printf("Received from %d (%zu bytes) [[%s]]\n", pid2, sz2, buffer2);
        printf("Concatenated data: <<%s>>\n", concat);
    
    return 0;

产生了一个样本运行:

$ ./pipe43
String 1: 
String 2: 
Vultures keep the world clean.
child 2 wrote [Vultures keep the world clean.] to the parent process
Hypersonic transport planes are as ubiquitous as pink elephants
child 1 wrote [Hypersonic transport planes are as ubiquitous as pink elephants] to the parent process
The one child (69005) exited with status 0x0000
T'other child (69004) exited with status 0x0000
Received from 69004 (63 bytes) [[Hypersonic transport planes are as ubiquitous as pink elephants]]
Received from 69005 (30 bytes) [[Vultures keep the world clean.]]
Concatenated data: <<[Hypersonic transport planes are as ubiquitous as pink elephants]+[Vultures keep the world clean.]>>
$

【讨论】:

以上是关于在 fork 后使用读/写管道 2 字符串的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信

叉子过程不从管道读取

进程间管道通信

linux IPC总结——管道

C++笔记--Linux编程(11)-进程通信

实验八