为什么来自管道的消息在时间显示为char?用C语言

Naw*_*sef 0 c linux parent-child

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

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 
    }
}
Run Code Online (Sandbox Code Playgroud)

如下所示的输出,如果你注意到,字符就是形成句子:A发送到B:C 0,这是想要的输出,但每个字符显示在它自己的行上!

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

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

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

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

在日志中:来自A:ms的msg |?

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

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

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

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

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

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

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

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

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

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

在log:msg中来自A:0ь|?

Jon*_*ler 6

读取代码使用:

read(fd_log[READ], message_from_A, strlen(msg_to_log)+1)
Run Code Online (Sandbox Code Playgroud)

在父级中,你没有初始化,msg_to_log所以你可能得到0作为字符串长度(大多数是偶然的;当然不是设计),并且一次读取一个字符.不要strlen()在接收代码中使用; 使用sizeof()- 没有+1!


我试过使用sizeof()但它只给了我第一条消息,所以输出是:

In log: msg from A: A sent to B: C 0
Run Code Online (Sandbox Code Playgroud)

然后程序终止了

像这样?

$ ./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
]]
$
Run Code Online (Sandbox Code Playgroud)

除此之外有两个读取,一个用于条目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]]
$
Run Code Online (Sandbox Code Playgroud)

请注意,读取操作都获得了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;
}
Run Code Online (Sandbox Code Playgroud)

修改打印代码以打印缓冲区中的所有字符串并不难 - 有点繁琐,但对您来说有利于处理.