【发布时间】:2011-05-18 16:41:52
【问题描述】:
我的测试应用是
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char *argv[], char *envp[]) {
int fd[2];
if(pipe(fd) < 0) {
printf("Can\'t create pipe\n");
exit(-1);
}
pid_t fpid = fork();
if (fpid == 0) {
close(0);
close(fd[1]);
char *s = (char *) malloc(sizeof(char));
while(1) if (read(fd[0], s, 1)) printf("%i\n", *s);
}
close(fd[0]);
char *c = (char *) malloc(sizeof(char));
while (1) {
if (read(0, c, 1) > 0) write(fd[1], c, 1);
}
return 0;
}
我想在每个输入的字符后查看字符代码。但实际上 *s 仅在控制台中的 '\n' 之后打印。所以似乎stdin(desc 0的文件)被缓冲了。但是读取功能是无缓冲的,不是吗?我哪里错了。
UPD:我用的是 linux。
所以解决办法是
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
int main(int argc, char *argv[], char *envp[]) {
int fd[2];
if(pipe(fd) < 0) {
printf("Can\'t create pipe\n");
exit(-1);
}
struct termios term, term_orig;
if(tcgetattr(0, &term_orig)) {
printf("tcgetattr failed\n");
exit(-1);
}
term = term_orig;
term.c_lflag &= ~ICANON;
term.c_lflag |= ECHO;
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &term)) {
printf("tcsetattr failed\n");
exit(-1);
}
pid_t fpid = fork();
if (fpid == 0) {
close(0);
close(fd[1]);
char *s = (char *) malloc(sizeof(char));
while(1) if (read(fd[0], s, 1)) printf("%i\n", *s);
}
close(fd[0]);
char *c = (char *) malloc(sizeof(char));
while (1) {
if (read(0, c, 1) > 0) write(fd[1], c, 1);
}
return 0;
}
【问题讨论】:
-
请注意,这与缓冲无关。
-
代码不应该在退出之前将父级中的终端属性重置为
term_orig吗?您可能还应该让孩子在某个时候退出——在父母关门后,它会不断地从read()得到 0。但是,父级也处于无限循环中;该过程仅在发出信号时结束。您确实需要一个信号处理程序来调用tcsetattr(),并使用您可能获得的主要信号的原始终端值(可以处理):HUP、INT、QUIT 也许,PIPE 和 TERM 是一个很好的集合。当然,你不能对 KILL 或 STOP 做任何事情。