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

时间:2009-07-26 15:47:08

标签: 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 handling */ }
    return c;
}

这会从终端读取单个字符。如果在某个时间范围内没有收到任何输入(由termios结构中的c_cc [VTIME]值指定),则read()返回0,并再次调用get_input()。

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

那么,如果从终端窗口运行app,然后终端窗口关闭,我怎样才能正常退出app?问题是read()永远不会返回-1,因此错误条件与read()返回0的正常情况无法区分。所以我看到的唯一解决方案是放入一个计时器,并假设存在错误条件read返回0比c_cc [V_TIME]中指定的时间快。但这个解决方案充其量只是hacky,我希望有更好的方法来处理这种情况。

有任何想法或建议吗?

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

您应该使用select而不是终端设置来处理超时。如果终端配置没有超时,那么除了EOF之外,它永远不会在读取时返回0。

选择为您提供超时,而读取会在关闭时为您提供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 */
}

答案 2 :(得分:0)

读取应该在EOF上返回0。即它不会成功读取任何内容。 在这种情况下,你的函数将返回0!

您应该做的是将read返回的值与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 */
        }
}