对于UNIX操作系统类中的一个练习,我应该开发一个程序,其中两个同级进程通过管道进行通信。一个进程(生产者)应该从stdout中读取字符串并将其发送给另一个进程,后者必须将字符串转换为大写,然后再次将其打印到stdout。字符串";结束";终止兄弟姐妹和父进程。
该程序运行良好,但当试图从用户那里读取整个短语而不是单个字符串时,它会崩溃。
这是我的主要部分:
int main(void) {
int child_status, fd[2];
if (pipe(fd)) {
fprintf(stderr, "Error: Could not create pipe.n");
return EXIT_FAILURE;
}
if (!fork()) {
// child1
producer(fd);
exit(0);
} else if (!fork()) {
// child2
consumer(fd);
exit(0);
} else {
// father
pid_t pid;
...
生产者流程:
void producer(int *fd) {
char buff[BUFFSIZE];
char *line;
close(fd[0]);
while (1) {
fflush(stdout);
fprintf(stdout, "Insert string:t");
scanf("%[^n]s%*c", buff);
fflush(stdout);
line = strdup(buff);
printToPipe(fd[1], line);
if (!strcmp(line, "end")) // Special string terminates process
return;
sleep(1);
}
return;
}
以及消费者流程:
void consumer(int *fd) {
char *buff;
close(fd[1]);
while (1) {
if ( (buff = readFromPipe(fd[0])) == NULL ) {
close(fd[0]);
return;
}
fprintf(stdout, "%sn", strToUpper(buff));
fflush(stdout);
}
return;
}
printToPipe()和readfromPipe()直接实现了read()和write()系统调用。
意外行为:
一旦输入第一个短语并将其转换为大写,程序将进行无限循环,打印出提示和第一个大写短语(即:Insert string: TEST TEST
)。特别是:
- 尽管我考虑了字符(
scanf("%[^n]s%*c", buff);
),但会忽略后续扫描。如果我检查scanf返回值,则对于第一次迭代之后的所有迭代 - 这似乎是一个难题;自我维持";它本身和它的输出:它不等待通过管道的新输入,并不断打印转换后的短语
尽管我考虑了字符,但后续扫描将被忽略
代码从不读取'n'
scanf("%[^n]s%*c", buff);
是个问题@John Bollinger。
-
"%[^n]"
将无限数量的非'n
字符读取到buff
中,可能会溢出buff
。它比gets()
更糟糕。如果至少读取了1个非'n'
字符,则会在buff
后面附加一个空字符,否则扫描将停止。 -
"s"
与's'
匹配,这在上述之后是不期望的——仅为'n'
,因此扫描停止而不消耗任何'n'
。 -
该格式的其余部分永远不会执行。
代码从不检查输入函数的返回值
通过检查scanf()
的返回值,buff
的内容可能是不变的或不确定的。
// scanf("%[^n]s%*c", buff);
if (scanf("%[^n]s%*c", buff) == 1) {
; // OK to use `buff`
}
OP的scanf()
可能会消耗第一行的大部分,将'n'
留在stdin
中,但第二个scanf()
调用在尝试读取第一行的'n'
时肯定会立即停止。这可能会使buff
保持不变。
使用fgets()
从stdin
读取输入的行,并另存为字符串@xing
// scanf("%[^n]s%*c", buff);
if (fgets(buff, sizeof buff, stdin) == NULL) {
; // Handle end-of-file or rare input error
break;
}
要从输入行中删除'n'
,请参阅此答案和其他答案
代码可以将'n'
保留在字符串中,并且在打印时不追加。
//fprintf(stdout, "%sn", strToUpper(buff));
fprintf(stdout, "%s", strToUpper(buff));
这将更好地处理超过BUFFSIZE
的长行输入,因为多余的字符只是留给下一次迭代。
OP可能需要调整CCD_ 29测试以考虑可能的尾随CCD_。
一个进程(生产者)应该从stdout读取字符串。。。。
详细信息:生产者不是从stdout
读取字符串,而是从stdin
将行读取到串中。