非规范终端I/O应用程序的Linux终端问题

非规范终端I/O应用程序的Linux终端问题,linux,terminal,termios,Linux,Terminal,Termios,我有一个用C编写的小应用程序,设计用于在Linux上运行。该应用程序的一部分接受来自键盘的用户输入,并使用非规范终端模式,以便能够响应每次按键 接受输入的代码部分是一个简单的函数,在循环中重复调用: char get_input() { char c = 0; int res = read(input_terminal, &c, 1); if (res == 0) return 0; if (res == -1) { /* snip error handl

我有一个用C编写的小应用程序,设计用于在Linux上运行。该应用程序的一部分接受来自键盘的用户输入,并使用非规范终端模式,以便能够响应每次按键

接受输入的代码部分是一个简单的函数,在循环中重复调用:

char get_input()
{
    char c = 0;
    int res = read(input_terminal, &c, 1);
    if (res == 0) return 0;
    if (res == -1) { /* snip error handling */ }
    return c;
}
这将从终端读取单个字符。如果在某个时间段内没有收到任何输入(由termios结构中的c_cc[VTIME]值指定),read()返回0,并再次调用get_input()

这一切都很好,但我最近发现,如果在终端窗口中运行此应用程序,然后关闭终端窗口而不终止应用程序,则应用程序不会退出,而是启动到CPU密集型无限循环中,其中read()连续返回0而不等待

那么,如果应用程序从终端窗口运行,然后终端窗口关闭,我如何让它优雅地退出呢?问题是read()从不返回-1,因此错误条件与read()返回0的正常情况无法区分。因此,我看到的唯一解决方案是加入一个计时器,并假设如果read返回的0比c_cc[V_time]中指定的时间快,则存在一个错误条件。但这个解决方案充其量也似乎有些老套,我希望有更好的方法来处理这种情况


有什么想法或建议吗?

在程序退出之前,您是否正在捕捉信号并重置内容?我认为SIGHUP是你需要关注的一个。如果从read()返回时开关打开,则可能在信号处理程序中设置一个开关。清除并退出。

read在EOF时应返回0。也就是说,它不会成功读取任何内容。 在这种情况下,您的函数将返回0

您应该做的是将读取返回的值与1和进程异常进行比较。 也就是说,你要求一个,但你得到了一个吗

如果返回-1,您可能需要处理errno==EINTR

char get_input() { char c = 0; int res = read(input_terminal, &c, 1); switch(res) { case 1: return c; case 0: /* EOF */ case -1: /* error */ } } char get_input() { 字符c=0; int res=读取(输入端&c,1); 开关(res){ 案例1: 返回c; 案例0: /*EOF*/ 案例1: /*错误*/ } }
您应该使用select而不是终端设置来处理超时。如果终端配置为无超时,则在读取时它将永远不会返回0,EOF除外

Select为您提供超时,read为您提供关闭时的0

rc = select(...);
if(rc > 0) {
        char c = 0;
        int res = read(input_terminal, &c, 1);
        if (res == 0) {/* EOF detected, close your app ?*/}
        if (res == -1) { /* snip error handling */ }
        return c;
} else if (rc == 0) {
   /* timeout */
   return 0;
} else {
   /* handle select error */
}