将终端设置为原始模式:仅在按下下一个键后才显示字符

时间:2017-07-27 11:10:35

标签: c++ c linux ssh

我正在关注如何编写基本SSH客户端的教程http://api.libssh.org/master/libssh_tutor_shell.html

我不希望ENTER键在(本地)终端中作为换行符回显。此外,我希望输入在准备好后立即读取和发送,而不是在按下ENTER后。

使用下面的代码,我尝试完成此任务。

然而,问题在于,在客户终端中,每当按下一个键时,在下一次按键之后首先显示该字符。这种行为的原因是什么?

此功能确定是否按下了某个键:

int kbhit()
{
    struct timeval tv = {0L, 0L};
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(0, &fds);
    return select(1, &fds, NULL, NULL, &tv);
}

从/向服务器读取/发送数据:

struct termios term_attr;
struct termios old_attr;

tcgetattr(STDIN_FILENO, &old_attr);
cfmakeraw(&term_attr);
tcsetattr(STDIN_FILENO, TCSANOW, &term_attr);

while (ssh_channel_is_open(channel) && !ssh_channel_is_eof(channel))
{
    nbytes = ssh_channel_read_nonblocking(channel, buff, sizeof(buff), 0);

    if (nbytes < 0)
    {
        return SSH_ERROR;
    }

    if (nbytes > 0)
    {
        nwritten = write(1, buff, nbytes);

        if (nwritten != nbytes)
        {
            return SSH_ERROR;
        }
    }

    if (!kbhit)
    {
        usleep(5000L);
        continue;
    }

    nbytes = read(0, buff, sizeof(buff));

    if (nbytes < 0)
    {
        return SSH_ERROR;
    }

    if (nbytes > 0)
    {
        nwritten = ssh_channel_write(channel, buff, nbytes);

        if (nwritten != nbytes)
        {
            return SSH_ERROR;
        }
    }
}

tcsetattr(STDIN_FILENO, TCSANOW, &old_attr);

1 个答案:

答案 0 :(得分:0)

您的程序将所有时间都用在read函数中。因此,在敲击密钥之后,它永远不会调用ssh_channel_read_nonblocking

这是流程:

  1. 我按了一把钥匙。
  2. 您将该密钥发送到另一方。
  3. 由于if (!kbhit)为真(因为kbhit不为NULL),我们会转到read
  4. 另一方在ssh频道上向我们发送回音,但由于我们在stdin上read被阻止,我们无法读取它。
  5. 您点击下一个键,我们循环播放,然后拨打ssh_channel_read_nonblocking,获取回音并回显它。
  6. 也许你应该调用kbhit函数而不是测试函数指针是否为假。