如何在C语言中使用select()函数从键盘读取输入

10

我正在尝试使用select()读取键盘输入,但遇到了问题,我不知道如何从键盘读取并使用文件描述符来实现。有人告诉我要使用STDIN和STDIN_FILENO来解决这个问题,但我仍然感到困惑。
我该如何做?


4
如果你不熟悉POSIX编程,这将是一件相当棘手的事情。首先,你需要设置终端模式,以便设备不会缓冲接收到的字符。 - antlersoft
1
除非它是作业的一部分,否则不需要使用select()。你可以直接使用fread(STDIN...)或read(STDIN_FILENO...)。 - Pete Wilson
2
如果您需要完全的终端控制(按键等),最好使用类似于ncurses的终端库(也有Windows版本),这样会更好。 - Kerrek SB
Pete Wilson:如果在用户按键之前套接字上收到消息,则fread(stdin ...)不会像select一样快速返回。在Linux中,我使用了select。在Windows中则更难。 - Windows programmer
您能否澄清为什么需要使用select来读取键盘输入?通常,当您需要从一系列描述符或输入中读取时,应使用select调用,因为它允许程序监视多个文件描述符,等待一个或多个文件描述符成为某种I / O操作(例如,可能的输入)的“就绪”。 - Karthik Balaguru
3个回答

6
你的问题听起来有些混淆。 select() 用于阻塞直到有输入可用。但你需要使用普通的文件读取函数(如readfreadfgetc等)进行实际的读取。
以下是一个快速示例。它会阻塞,直到stdin至少有一个字符可供读取。但是,除非你将终端更改为某种未加工模式,否则它会一直阻塞,直到你按下回车键,此时键入的任何字符都会被刷新到文件缓冲区(从某个终端缓冲区)。
#include <stdio.h>
#include <sys/select.h>

int main(void) {
    fd_set s_rd, s_wr, s_ex;
    FD_ZERO(&s_rd);
    FD_ZERO(&s_wr);
    FD_ZERO(&s_ex);
    FD_SET(fileno(stdin), &s_rd);
    select(fileno(stdin)+1, &s_rd, &s_wr, &s_ex, NULL);
    return 0;
}

非常感谢,这确实解答了我的问题。 - drum

6
正如先前所述,通过使用select,您可以监视例如标准输入以检查输入数据是否已经准备好读取。如果可用,则可以使用例如fgets安全地将输入数据读取到某个缓冲区中,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    fd_set rfds;
    struct timeval tv;
    int retval, len;
    char buff[255] = {0};

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

    /* Wait up to five seconds. */
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv);

    if (retval == -1){
        perror("select()");
        exit(EXIT_FAILURE);
    }
    else if (retval){
        /* FD_ISSET(0, &rfds) is true so input is available now. */

        /* Read data from stdin using fgets. */
        fgets(buff, sizeof(buff), stdin);

        /* Remove trailing newline character from the input buffer if needed. */
        len = strlen(buff) - 1;
        if (buff[len] == '\n')
            buff[len] = '\0';

        printf("'%s' was read from stdin.\n", buff);
    }
    else
        printf("No data within five seconds.\n");            

    exit(EXIT_SUCCESS);
}

1
也许你想知道如何在“WINDOWS”上查看键盘输入? 在Windows上,无法从select()获取STDIN的结果。您应该使用PeekConsoleInput()。 并像以下示例一样使用stdin的句柄。
hStdin = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, ...

标准输入可能变为管道输入。如果是这样,你将无法获取任何键盘输入。

附言:如果你没有询问关于Windows的问题,非常抱歉。


Windows 没有在我脑海中出现。很好的挽救:考虑到所有可能性。 - luser droog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接