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

发布于 2024-07-29 16:35:54 字数 770 浏览 2 评论 0原文

我有一个用 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。

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

有什么想法或建议吗?

I have a small app written in C designed to run on Linux. Part of the app accepts user-input from the keyboard, and it uses non-canonical terminal mode so that it can respond to each keystroke.

The section of code that accepts input is a simple function which is called repeatedly in a loop:

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;
}

This reads a single character from the terminal. If no input is received within a certain timeframe, (specified by the c_cc[VTIME] value in the termios struct), read() returns 0, and get_input() is called again.

This all works great, except I recently discovered that if you run this app in a terminal window, and then close the terminal window without terminating the app, the app does not exit but launches into a CPU intensive infinite loop, where read() continuously returns 0 without waiting.

So how can I have the app exit gracefully if it is run from a terminal window, and then the terminal window is closed? The problem is that read() never returns -1, so the error condition is indistinguishable from a normal case where read() returns 0. So the only solution I see is to put in a timer, and assume there is an error condition if read returns 0 faster than the time specified in c_cc[V_TIME]. But that solution seems hacky at best, and I was hoping there is some better way to handle this situation.

Any ideas or suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧伤还要旧人安 2024-08-05 16:35:55

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

Are you catching signals and resetting things before your program exits? I think SIGHUP is the one you need to focus on. Possibly set a switch in the signal handler, if switch is on when returning from read() clean up and exit.

岁月流歌 2024-08-05 16:35:55

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

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 */
}

You should handle timeout with select rather than with terminal settings. If the terminal is configured without timeout, then it will never return 0 on a read except on EOF.

Select gives you the timeout, and read gives you the 0 on close.

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 */
}
又爬满兰若 2024-08-05 16:35:55

读取应在 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 */
        }
}

Read should return 0 on EOF. I.e. it will read nothing successfully.
Your function will return 0 in that case!

What you should do is compare value returned from read with 1 and process exception.
I.e. you asked for one, but did you get one?

You will probably want to handle errno==EINTR if -1 is returned.

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 */
        }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文