4

我有一个用 C 编写的非常简单的 TCP 服务器。它无限期地运行,等待连接。在 Windows 上,我select用来检查套接字上的活动,如果没有,我有以下代码允许我通过按键盘上的“q”退出:

if( kbhit() ) {
   char c = getch();
   if( c == 'q' ) break;
}

这在 unix 上不起作用,因为kbhit不存在并且getch工作方式不同。我找到了一些用于更改终端设置并允许逐个字符输入的示例代码。tcsetattr调用 init 函数后,我打开 /dev/stdin (使用O_NONBLOCK)并读取一个字符,但read( f, &c, 1 )会阻塞直到命中一个字符。

我想我可以生成一个单独的线程并让它无限期地等待,然后如果用户点击“q”,则向第一个线程发出信号,但这似乎有点笨拙。肯定有更简单的方法吗?

4

3 回答 3

5

将标准输入添加到您的选择句柄列表中,如果它有数据,则调用 read 从中读取一个字符。

于 2008-10-08T18:25:45.643 回答
1

相反,从您的

read( f, &c, 1 )

选择通话。当 f 准备好读取时,一个字符被按下,read() 不会阻塞。

于 2008-10-08T19:02:57.533 回答
1

在 Unix 中,无论是在系统控制台还是在 X 终端窗口中,键盘 I/O 都通过虚拟终端。如今,设备 /dev/tty 是访问进程控制终端的常用方式。除了打开/关闭/读取/写入之外的设备操作都由该特定设备的 ioctl(2) 系统调用处理。你想要做的一般想法是

打开控制终端(可能是也可能不是标准输入)

更改该终端上的操作模式以返回而无需等待完整的输入行(这是正常默认值)

继续执行程序的其余部分,知道从该终端(可能是标准输入)读取可能会返回部分行甚至零个字符,而不会成为错误或终止条件。


在C-programming faq中可以找到有关如何执行第二步的详细答案。他们还指出这是一个操作系统问题,而不是语言问题。它们提供了九种可能性,但与这个问题相关的三个主要可能性是

  1. 使用 curses(3) 库
  2. 旧的 BSD 风格系统,使用 sgttyb 设置 CBREAK 或 RAW
  3. Posix 或旧 System V 风格的系统,使用 TCGETAW/TCSETAW 将 c_cc[VMIN] 设置为 1 并将 c_cc[VTIME] 设置为 0。

Following a couple of references in the C FAQ could lead to to this page of kbhit code fragments.

于 2008-10-17T16:47:05.403 回答