为什么来自管道的消息有时显示为字符?在C语言中

Why messages from a pipe are being displayed as a char at at time? In C language

我正在尝试使用管道读取从子进程发送到父进程的消息。我在这里提问并得到了一些帮助,我能够收到消息。但问题是消息一次显示一个字符。我不知道为什么。这是我的代码:

int main(int argc, char *argv[]){

    printf("\nWritten by Nawar Youssef\n");

    int i, x, fd_log[2], fd_A_B[2], pipe_size=500;
    char ch, message_from_A[pipe_size], message_from_B[pipe_size],
                        msg_to_log[pipe_size], msg_to_B[pipe_size];

    pipe(fd_log);
    pipe(fd_A_B);

    //fork process A
    if (fork()==0) { //child
        printf("Inside process A\n");
        for (i=0; i < 10; i++) {
            //creat new a record (C or D 0 to/or 9)
            x = (rand() % 2);
            if (x == 1)
                ch='C';
            else
                ch='D';

            //write msg to log pipe
            sprintf(msg_to_log, "A sent to B: %c %d\n", ch, i);
            printf("wirtten to log pipe--> %s\n", msg_to_log);
            close(fd_log[READ]);
            write(fd_log[WRITE], msg_to_log, strlen(msg_to_log)+1);
        }//end for()
        close(fd_log[WRITE]);
        _exit(1); //process A

    }
    else { //parent
        close(fd_log[WRITE]);
        while (read(fd_log[READ], message_from_A, strlen(msg_to_log)+1) > 0 ) {
            sleep(1);
            printf("\nIn log: msg from A: %s", message_from_A);
        }
        close(fd_log[READ]); //this line won't affect output 
    }
}

输出如下,如果你注意到的话,这些字符构成了句子:A sent to B: C 0,这是想要的输出,但每个字符都显示在它自己的行上!

在日志中:来自 A 的消息:Aь|?

在日志中:来自 A 的消息:ь|?

在日志中:来自 A 的消息:sь|?

在日志中:来自 A 的消息:eь|?

在日志中:来自 A 的消息:nь|?

在日志中:来自 A 的消息:tь|?

在日志中:来自 A 的消息:ь|?

在日志中:来自 A 的消息:tь|?

在日志中:来自 A 的消息:oь|?

在日志中:来自 A 的消息:ь|?

在日志中:来自 A 的消息:Bь|?

在日志中:来自 A 的消息::ь|?

在日志中:来自 A 的消息:ь|?

在日志中:来自 A 的消息:Cь|?

在日志中:来自 A 的消息:ь|?

在日志中:来自 A 的消息:0ь|?

读取代码使用:

read(fd_log[READ], message_from_A, strlen(msg_to_log)+1)

并且在父级中,您还没有初始化 msg_to_log 因此您可能得到 0 作为字符串长度(大部分是偶然的;当然不是设计的),并且一次读取一个字符。不要在接收码中使用strlen();使用 sizeof() — 没有 +1!


I tried using sizeof() but it gave me only the first message, so the output was:

In log: msg from A: A sent to B: C 0

and then the program terminated

像这样?

$ ./piperead
Inside process A
written to log pipe--> A sent to B: C 0

written to log pipe--> A sent to B: D 1

written to log pipe--> A sent to B: C 2

written to log pipe--> A sent to B: C 3

written to log pipe--> A sent to B: C 4

written to log pipe--> A sent to B: C 5

written to log pipe--> A sent to B: D 6

written to log pipe--> A sent to B: D 7

written to log pipe--> A sent to B: C 8

written to log pipe--> A sent to B: C 9

In log: msg from A: [[A sent to B: C 0
]]
In log: msg from A: [[A sent to B: C 8
]]
$

除此之外有两个读取,一个用于条目 0..7,一个用于条目 8..9。

这是对您的代码稍作修改后的版本。问题在于您在管道上写入空字节,而 read() 在一次操作中读取多条消息,但 printf() 在第一个空字节处停止。

这是您的代码的改编版本的输出:

$ ./piperead
Inside process A
0: written to log pipe--> [[A sent to B: C 0]]
1: written to log pipe--> [[A sent to B: D 1]]
2: written to log pipe--> [[A sent to B: C 2]]
3: written to log pipe--> [[A sent to B: C 3]]
4: written to log pipe--> [[A sent to B: C 4]]
5: written to log pipe--> [[A sent to B: C 5]]
6: written to log pipe--> [[A sent to B: D 6]]
7: written to log pipe--> [[A sent to B: D 7]]
8: written to log pipe--> [[A sent to B: C 8]]
9: written to log pipe--> [[A sent to B: C 9]]
In log: msg from A: 85: 16: [[A sent to B: C 0]]
In log: msg from A: 85: 16: [[A sent to B: C 5]]
$

请注意,读取操作都获得了 85 个字节的数据,但只有前 16 (17) 个字节作为 printf() 打印的字符串可见。管道中数据的划分取决于很多因素。这是在一台有 6 个 CPU 的机器上 运行。其他时候我 运行 它并在一次操作中读取了所有 170 个字节;我也得到了 119:51 拆分和 136:34 (这是第一个示例中显示的),任何其他 n*17:(10-n)*17 比率也是可能的。

这是修改后的来源:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

enum { READ = 0, WRITE = 1 };

int main(void)
{
    int i;
    int x;
    int fd_log[2];
    int pipe_size = 500;
    char ch;
    char message_from_A[pipe_size];
    char msg_to_log[pipe_size];

    pipe(fd_log);

    if (fork() == 0) // child
    {
        printf("Inside process A\n");
        for (i = 0; i < 10; i++)
        {
            // creat new a record (C or D 0 to/or 9)
            x = (rand() % 2);
            if (x == 1)
                ch = 'C';
            else
                ch = 'D';

            // write msg to log pipe
            sprintf(msg_to_log, "A sent to B: %c %d", ch, i);
            printf("%d: written to log pipe--> [[%s]]\n", i, msg_to_log);
            write(fd_log[WRITE], msg_to_log, strlen(msg_to_log) + 1);
        } // end for()
        close(fd_log[READ]);
        close(fd_log[WRITE]);
        _exit(1); // process A
    }
    else // parent
    {
        int nbytes;
        close(fd_log[WRITE]);
        while ((nbytes = read(fd_log[READ], message_from_A, sizeof(message_from_A))) > 0)
        {
            printf("In log: msg from A: %d: %zu: [[%s]]\n", nbytes, strlen(message_from_A),
                   message_from_A);
            sleep(1);
        }
        close(fd_log[READ]); // this line won't affect output
    }
    return 0;
}

修改打印代码以打印缓冲区中的所有字符串并不难 — 有点繁琐,但对您来说是个好东西。