非规范终端 I/O 应用程序的 Linux 终端问题
我有一个用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您是否在程序退出之前捕获信号并重置内容? 我认为 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.
您应该使用 select 而不是终端设置来处理超时。 如果终端配置为没有超时,那么除了 EOF 之外,它在读取时永远不会返回 0。
Select 给出超时值,read 给出关闭时的 0 值。
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.
读取应在 EOF 处返回 0。 即它不会成功读取任何内容。
在这种情况下你的函数将返回 0!
您应该做的是将读取返回的值与 1 进行比较并处理异常。
也就是说,您要了一份,但您收到了吗?
如果返回 -1,您可能需要处理 errno==EINTR。
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.