为什么来自管道的消息有时显示为字符?在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;
}
修改打印代码以打印缓冲区中的所有字符串并不难 — 有点繁琐,但对您来说是个好东西。
我正在尝试使用管道读取从子进程发送到父进程的消息。我在这里提问并得到了一些帮助,我能够收到消息。但问题是消息一次显示一个字符。我不知道为什么。这是我的代码:
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;
}
修改打印代码以打印缓冲区中的所有字符串并不难 — 有点繁琐,但对您来说是个好东西。