c - IPC 使用 fork() 和 pipe()

标签 c unix pipe output fork

我正在尝试使用管道模拟调用者和接收者之间的对话。我正在 fork 一个进程,让父进程成为接收者,让子进程成为调用者。

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LEN 25
#define READ_END 0
#define WRITE_END 1

int main()
{
    int fd[2];
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }

    pid_t pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } 

    // the parent process is the receiver
    if (pid > 0) {
        close(fd[WRITE_END]);
        char buffer[BUF_LEN + 1] = "";
        do {
            read(fd[READ_END], buffer, sizeof buffer);
            if (strcmp(buffer, "")) {
                printf("Received %s\n", buffer);
            }
            strcpy(buffer, "");
        } while (strcmp(buffer, "Bye!"));
        close(fd[READ_END]);
    } else {
        close(fd[READ_END]);
        // const char *msg = "Hello";
        char buffer[BUF_LEN + 1] = "";
        bool end_call = false;
        do {
            printf("Caller: ");
            fgets(buffer, sizeof buffer, stdin);
            if (strcmp(buffer, "Bye!")) {
                end_call = true;
            }
            // printf("Sent %s\n", buffer);
            write(fd[WRITE_END], buffer, strlen(buffer) + 1);
        } while (!end_call);
        close(fd[WRITE_END]);
    }
    return 0;
}

但是当我运行它时,我得到了这个意外的输出:

Caller: Hi
Received Hi

HI
Hello
Bye!
^C

接收器停止工作,它没有接收到我提供的输入。输出中还会出现额外的换行符。为什么会这样?

编辑: 正如 Dmitri 指出的那样,我已经更改了调用方中的 strcmp 测试和接收方中的 printf 语句。

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LEN 25
#define READ_END 0
#define WRITE_END 1

int main()
{
    int fd[2];
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed"); return 1; }

    pid_t pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } 

    // the parent process is the receiver
    if (pid > 0) {
        close(fd[WRITE_END]);
        char buffer[BUF_LEN + 1] = "";
        do {
            read(fd[READ_END], buffer, sizeof buffer);
            if (strcmp(buffer, "")) {
                printf("Received %s", buffer);
            }
            strcpy(buffer, "");
        } while (strcmp(buffer, "Bye!"));
        close(fd[READ_END]);
    } else {
        close(fd[READ_END]);
        // const char *msg = "Hello";
        char buffer[BUF_LEN + 1] = "";
        bool end_call = false;
        do {
            printf("Caller: ");
            fgets(buffer, sizeof buffer, stdin);
            if (!strcmp(buffer, "Bye!")) {
                end_call = true;
            }
            // printf("Sent %s\n", buffer);
            write(fd[WRITE_END], buffer, strlen(buffer) + 1);
        } while (!end_call);
        close(fd[WRITE_END]);
    }
    return 0;
}

但是收到“Bye!”后仍然没有退出。

Caller: hi
Received hi
Caller: Hello
Received Hello
Caller: Bye!
Received Bye!
Caller: Bye!
Received Bye!
Caller: ^C

最佳答案

strcmp() 成功返回 0。但是您的代码还存在其他几个问题:

  1. 字符串永远不会等于“Bye!”,将附加一个新行以及表示字符串结尾的空字符(总共 6 个字符)。

  2. 管道使用流而不是“数据包”,您永远不知道一次调用 read() 会收到多少字节。它可能是不完整的字符串,或者如果数据发送速度非常快,您可能会将 2 个字符串粘在一起。您需要实现自己的“协议(protocol)”来从流中解析数据。

  3. 您没有检查另一侧的管道是否关闭(读取将返回 0)

  4. 您在输出中得到额外的新行,因为它附加到 fgets() 读取的字符串

  5. 输出可能会困惑,因为您无法控制进程何时刷新到 stdout(某种竞争条件,但不会崩溃)。

关于c - IPC 使用 fork() 和 pipe(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40227868/

相关文章:

c++ - "dynamically allocated memory emulating multi-dimensional array"的正确术语?

c - 在什么情况下(如果有的话)C 中前缀和后缀递增/递减运算符之间的性能存在差异?

linux - 如何使用 CUPS(lp 命令)打印多页 tiff 文件?

linux - 查找文本文件中最长的单词

清除部分虚拟内存?

c++ - 如何在C或C++中包装参数并将其传递给system或exec *

java - Unix 上 Java 中不区分大小写的目录访问

python - 在 python 进程之间传递二进制数据

c - 当第二个子进程关闭读取管道末尾时杀死第一个子进程

在 Windows 中创建匿名管道