【问题标题】:getch() does display most recently typed character and skips every other character enteredgetch() 确实显示最近输入的字符并跳过输入的所有其他字符
【发布时间】:2017-07-10 15:32:00
【问题描述】:

正在完成一项课堂作业,并且已经与 ncurses 斗争了一段时间(这对我来说是新的)。创建一个能够通过网络与同一程序的另一个实例进行通信的程序。该程序的一部分是从键盘交互地获取字符并将它们发送到接收端。 (我们被建议使用单线程方法并在 ncurses 中使用 getch,并使用来自 getch 的非阻塞输入)。

我遇到的问题是我的getch 有我无法弄清楚的行为。在不同的变体中,它要么显示我键入的每个其他字符,并且在键入另一个字符之前不会显示最近键入的字符。我使用nodelay() 来获取实时输入,但是。

这是我的 ncurses 显示器的设置。 (注意:我使用了noecho(),因为稍后我不想显示输入的每个字符)。

/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();

这是我编写的代码,可用于getch 并通过套接字发送/接收数据。

while(1) {
    rfdset = master;

    if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(EXIT_FAILURE);
    }

    ch = getch();

    if (ch != ERR) {
        printw("%c",ch);
        write(direct, &ch, 1); // direction to send data
    }

    for(i = 0; i <= maxfd; i++) {
        if (FD_ISSET(i, &rfdset)) {
            bzero(msgbuf, MSGSIZE);
            idx = read(i, msgbuf, MSGSIZE);
            if (i != STDIN)
                printw("%s",msgbuf); // display received msg
        }
    }
}

当我在应用程序的任何一端运行并输入数据时,我得到如下结果:

Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2

Computer 2 message recv'd: tsig2

因此,我确信getch 导致了我的大部分问题,而且我在实施过程中一定遗漏了或做错了什么。任何建议表示赞赏。

编辑 1:

我设法通过删除 for 循环并直接检查套接字的输入来解决 所有其他字符问题。我很困惑为什么这会解决它。现在我唯一剩下的问题是为什么在输入字符后才显示字符。这是我在while循环中修改的代码:

while(1) {
    rfdset = master;

    if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(EXIT_FAILURE);
    }

    ch = getch();

    if (ch != ERR) {
        printw("%c",ch);
        write(direct, &ch, 1);
    }

    /* check for incoming data from left socket */
    if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
        bzero(leftmsg, MSGSIZE);
        idx = read(lcsad, leftmsg, MSGSIZE);
        leftmsg[idx] = 0;
        printw("%s", leftmsg);
        lm = 1;
    }

    /* check for incoming data from right socket */
    if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
        bzero(rghtmsg, MSGSIZE);
        idx = read(rsd, rghtmsg, MSGSIZE);
        rghtmsg[idx] = 0;
        printw("%s", rghtmsg);
        rm = 1;
    }

    /* check and send left message onward */
    if (lm && !NORIGHT) {
        write(direct, leftmsg, MSGSIZE);
    }

    /* check and send right message onward */
    if (rm && !NOLEFT) {
        write(direct, rghtmsg, MSGSIZE);
    }
    lm, rm = 0;
}

【问题讨论】:

  • 请注意,msgbuf 不一定是空字符终止的。建议read(i, msgbuf, MSGSIZE-1);
  • 对于调试,在输出中添加括号可能会很有用。printw("%c",ch); --> printw("&lt;%c&gt;",ch);printw("&lt;%s&gt;",msgbuf);
  • 谢谢@chux,这是一个很好的观点,我需要解决一些问题。 (也感谢您的编辑)。我会试试的。
  • @chux - 所以我把括号放在里面,这是我输入“测试键盘输入”&lt;t&gt;&lt;s&gt;&lt; &gt;&lt;e&gt;&lt;b&gt;&lt;a&gt;&lt;d&gt;&lt;i&gt;&lt;p&gt;&lt;t&gt;&lt; &gt;得到的结果,两台机器上的结果都是一样的。
  • 关于所有其他字符问题。代码读取ch = getch();,然后在for 循环中读取idx = read(0, msgbuf, MSGSIZE);。这不也是stdin的读法吗?

标签: c sockets ncurses getch


【解决方案1】:

问题是因为你的 select 调用没有指定超时(最后一个参数是NULL),它会阻塞直到有一些挂起的 I/O(例如下一个字符你输入)。此时,程序继续执行getch 调用,该调用执行refresh(与printw 调用中的字符相呼应)。

指定一个较短的超时时间,例如 10 毫秒,可以改善事情,例如,

struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;

并将调用中myTimeout的地址传递给select...

【讨论】:

  • 这解决了问题,感谢您的清晰解释。将超时添加到 select 解决了这个问题。
【解决方案2】:

如果使用 wgetch() 代替 getch() 可以解决您的问题,您可以尝试。

【讨论】:

  • 根据最近的编辑 - 我修复了所有其他字符问题,现在我被困在 为什么在输入字符后才显示字符。
猜你喜欢
  • 1970-01-01
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多