C 当程序关闭并且数据从tail-f通过管道传输时,为什么fgets挂起?
我正在使用C 当程序关闭并且数据从tail-f通过管道传输时,为什么fgets挂起?,c,pipe,stdin,fgets,tail,C,Pipe,Stdin,Fgets,Tail,我正在使用tail-f读取日志,并将数据传输到我的ncurses程序 tail -f somelog | ./a.out 它工作得很好,只是当我按下q键时,程序不会退出,它只是挂起,直到一个字节被写入被跟踪的文件。使用cat somelog |/a.out时不会出现这种情况,我想这是因为没有遵循 看起来是行while(fgets(buf,1024,input)导致了问题。您知道为什么以及如何修复它吗?谢谢 // gcc app.c -lncurses // tail -f logfile
tail-f
读取日志,并将数据传输到我的ncurses程序
tail -f somelog | ./a.out
它工作得很好,只是当我按下q键时,程序不会退出,它只是挂起,直到一个字节被写入被跟踪的文件。使用cat somelog |/a.out
时不会出现这种情况,我想这是因为没有遵循
看起来是行while(fgets(buf,1024,input)
导致了问题。您知道为什么以及如何修复它吗?谢谢
// gcc app.c -lncurses
// tail -f logfile | ./a.out
#include <stdio.h>
#include <ncurses.h>
#include <fcntl.h>
#include <string.h>
void print_status(WINDOW * win, const char *str) {
init_pair(1, COLOR_RED, COLOR_WHITE);
clear();
mvwhline(win, 0, 0, ' ', COLS);
mvwaddnstr(win, 0, 0, str, COLS);
wrefresh(win);
}
void print_line(WINDOW * win, const char *str, int *i) {
init_pair(2, COLOR_RED, COLOR_BLACK);
if (*i > LINES - 2) {
*i = 1;
wclear(win);
}
mvwprintw(win, (*i)++, 0, str);
wrefresh(win);
}
int main() {
WINDOW *menu_win, *wi;
int i = 1, q = 1, fd1, fd2, is_atty = 1;
char buf[1024];
initscr();
clear();
halfdelay(5);
menu_win = newwin(1, COLS, 0, 0);
wi = newwin(LINES - 1, COLS, 1, 0);
keypad(menu_win, TRUE);
FILE *input = stdin;
if(!isatty(fileno(stdin))) {
is_atty = 0;
fd1 = open("/dev/tty", O_RDONLY);
fd2 = dup(fileno(stdin));
input = fdopen(fd2, "r");
freopen("/dev/tty", "r", stdin);
if(fileno(stdin) != 0) /* from ncurses dialog */
(void)dup2(fileno(stdin), 0);
close(fd1);
int flags = fcntl(fd2, F_GETFL);
// non-blocking fgets so getch works fine
fcntl(fd2, F_SETFL, flags|O_NONBLOCK);
}
print_status(menu_win, "Use arrow keys to go up and down");
while(q) {
switch(wgetch(menu_win)) {
case KEY_UP:
print_status(menu_win, "Moved up");
break;
case KEY_DOWN:
print_status(menu_win, "Moved down");
break;
case 'q':
q = 0;
break;
default:
if(is_atty) break;
while(fgets(buf, 1024, input) != NULL) {
print_line(wi, buf, &i);
}
break;
}
}
fclose(input);
close(fd2);
endwin();
return 0;
}
//gcc app.c-lncurses
//tail-f日志文件|/a.out
#包括
#包括
#包括
#包括
无效打印状态(窗口*win,常量字符*str){
初始对(1,红色,白色);
清除();
mvwhline(win,0,0,,,COLS);
mvwaddnstr(win、0、0、str、COLS);
雷弗斯(赢);
}
无效打印行(窗口*win,常量字符*str,整数*i){
初始对(2,红色,黑色);
如果(*i>行-2){
*i=1;
wclear(win);
}
mvwprintw(win,(*i)+,0,str);
雷弗斯(赢);
}
int main(){
窗口*menu_win,*wi;
int i=1,q=1,fd1,fd2,是_atty=1;
char-buf[1024];
initscr();
清除();
半延迟(5);
menu_win=newwin(1,COLS,0,0);
wi=newwin(行-1,COLS,1,0);
键盘(菜单,正确);
文件*input=stdin;
如果(!isatty(fileno(stdin))){
is_atty=0;
fd1=打开(“/dev/tty”,仅限Ordu);
fd2=dup(文件号(标准输入));
输入=fdopen(fd2,“r”);
freopen(“/dev/tty”,“r”,stdin);
如果(文件号(标准输入)!=0)/*来自ncurses对话框*/
(无效)dup2(文件号(标准输入),0);
关闭(fd1);
int flags=fcntl(fd2,F_GETFL);
//非阻塞FGET,因此getch工作正常
fcntl(fd2、F|U设置FL、标志| O|U非块);
}
打印状态(菜单“使用箭头键上下移动”);
while(q){
开关(wgetch(菜单_-win)){
案例编号:
打印状态(菜单“上移”);
打破
案例键向下:
打印状态(菜单“向下移动”);
打破
案例‘q’:
q=0;
打破
违约:
如果(正在)中断;
while(fgets(buf,1024,输入)!=NULL){
打印行(wi、buf和i);
}
打破
}
}
fclose(输入);
关闭(fd2);
endwin();
返回0;
}
一旦您的代码调用fgets()
它将在fgets()
中保持阻塞状态,直到更多输入到达-或管道关闭
这不会发生在cat somelog |/a.out
上,因为正如您所怀疑的那样,cat
没有挂起等待更多数据写入文件。cat
继续发送数据,然后退出,关闭管道并导致fgets()
返回缓冲的数据并等待更多的数据,或者如果没有读取数据,返回NULL
。tail-f…
在到达文件末尾时不会退出并关闭管道-tail-f…
只会等待更多数据写入正在跟踪的文件,因此您对fgets()的调用
就坐在那里
那么为什么呢?因为fgets()
在获得换行符或EOF之前不会返回:
fgets()
从中最多读取一个小于大小的字符
流动
并将其存储到s指向的缓冲区中。读取在
EOF
或换行符
一旦您的代码调用了
fgets()
,它将在fgets()
中保持阻塞状态,直到更多输入到达-或者管道关闭
这不会发生在cat somelog |/a.out
上,因为正如您所怀疑的那样,cat
没有挂起等待更多数据写入文件。cat
继续发送数据,然后退出,关闭管道并导致fgets()
返回缓冲的数据并等待更多的数据,或者如果没有读取数据,返回NULL
。tail-f…
在到达文件末尾时不会退出并关闭管道-tail-f…
只会等待更多数据写入正在跟踪的文件,因此您对fgets()的调用
就坐在那里
那么为什么呢?因为fgets()
在获得换行符或EOF之前不会返回:
fgets()
从中最多读取一个小于大小的字符
流动
并将其存储到s指向的缓冲区中。读取在
EOF
或换行符
cat
发送一个EOF
,而tail-f
不发送,它只是保持管道打开。如果它是tail-100
,它的行为将类似于cat
。但是,当你按q
时,你识别的行不会被调用。你确实关闭了input
,但你没有关闭fd2
@alvits谢谢编辑编辑问题并添加了close(fd2)
。默认值:
案例仅在您按任意键时执行。当您按q
时,它执行case'q':
,随后导致while
循环终止。它不是fgets()
这导致它阻塞。管道在到达返回0时仍然打开;
。运行tail-f somelog | strace./a.out
。查看您的代码是否没有关闭管道。tail
将在收到SIGPIPE
时终止。记住,您有多个管道副本。在案例“q”中打印一些内容:
block。这将有助于您进行故障排除。@谢谢您的回复。进行一次strace,我看到q
存在循环并达到close(fs2)
,我还看到fd1=4
和fd2=5
,然后关闭4
,然后关闭0
,最后关闭