繁体   English   中英

使用fork()和pipe()的IPC

[英]IPC using fork() and pipe()

我正在尝试使用管道模拟呼叫者和接收者之间的对话。 我正在分叉一个进程,并使父进程成为接收方,而子进程成为调用方。

这是代码:

#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;
}

但是在收到“再见!”之后,它仍然没有退出。

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

成功时,strcmp()返回0。 但是您的代码还存在其他一些问题:

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

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

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

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

  5. 由于您无法控制何时将进程刷新到标准输出(某种竞争状况,但不会崩溃),因此输出可能会混乱。

将客户端中的测试更改为以下内容。 这将使孩子/父母进行交流。

    if (!strcmp(buffer, "Bye!")) {

客户端读取的缓冲区中有换行符(“再见!”,后跟换行符)。 无法匹配退出测试。 您可以尝试将其删除。

    fgets(buffer, sizeof buffer, stdin);
    buffer[strlen(buffer)-1]='\0';

在服务器端,请勿初始化缓冲区(仅在while-check之前)。 因为那样会重新初始化您要检查的字符串。

     strcpy(buffer, "");

如果需要,可以在运行read功能之前将其放置。

正如其他答案所指出的那样,您还可能遇到问题缓冲问题(匹配结束条件)和竞争条件(同时关闭fds)。 但是,我想这仅仅是“学习”的足够好例子。 祝好运。

由于fgets捕获了换行符,因此您需要测试Bye!\\n的退出条件,其中包括该换行符。 strcmp(buffer, "Bye!\\n")

这是解决@blackpen指出的否定问题的补充。

您的程序有几个问题。

首先,当fgets()读取一行时,将在末尾包含换行符(如果缓冲区中有足够的空间)。 您看到的额外换行符是因为发送的字符串包含一个,然后在接收器中打印该字符串时添加了另一个。 另外,您正在寻找字符串"Bye!" 决定何时退出...但是您实际得到的字符串是"Bye!\\n" 您需要将换行符从发件人从stdin读取的字符串的末尾去除,或者在打印和比较时考虑字符串中已经存在的换行符。

其次,在发送者中,检查退出时间时逻辑反转:您正在设置end_call = true; buffer 包含"Bye!" ,而不是何时进行。 这将导致发送方在发送第一个字符串而不是循环之后退出(同样,如上所述,需要固定比较以解决换行符)。 不是接收者提前停止,而是发送者……接收者由于下一个问题而永远运行。

在接收器中,您要在循环结束时清除缓冲区,就您检查"Bye!" 之前 "Bye!" 在循环测试中。 这样可以防止循环测试中的比较找到匹配项,因此循环是无限的。 而是在循环开始之前在fgets()之前清除缓冲区。 (再次,固定比较以在末尾考虑换行符)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM