循环以丢弃来自stdin,Linux C ++的伪变量输入

时间:2014-09-23 20:33:37

标签: c++ linux iostream

我正在尝试为我的linux机器编写一个c ++程序,它可以与一些响应简单ascii命令的工具进行交互。我认为,我遇到的问题是一个相当普遍的请求,但我对各种论坛的搜索却没有完全相同。

我的问题是:当我连接到乐器时,由于一些通信问题,它经常会产生一堆我不想要的不同长度的数据。机器打印的数据具有行结尾' \ r'。我一直在尝试编写一个简单的循环,它将继续读取并忽略数据,直到机器静音两秒钟,然后在暴风雨结束后继续执行一些数据请求。

在搜索论坛时,我发现了关于cin.ignorecin.syncgetlinecin.getline的大量线索。这些都看起来非常有用但是当我试图以应该简单的方式实现它们时,它们的表现从来没有像我预期的那样。

如果这是一个重复的帖子,我提前道歉,因为我原本以为我不是第一个想要丢弃垃圾输入的人,但我没有找到这样的帖子。

代码我一直在尝试几种不同的外观安排:

sleep(2);
cin.clear();
while ( cin.peek() != char_traits<char>::eof()) {
    //cin.sync();
    //cin.ignore(numeric_limits<streamsize>::max(),char_traits<char>::eof());
    cin.clear();
    char tmp[1];
    while ( cin.getline(tmp,80,'\r') ) {}
    cin.clear();
    sleep(2);
}

我从我的搜索中了解到,做某种while(!cin.eof())是不好的做法,但无论如何都要尝试使用grins以及while(getline(cin,str,'\r'))while(cin.ignore())。我在这里不知所措,因为我显然缺少一些东西。

思想?

编辑: - 最终代码 -

好的!这样做了!谢谢你指点我的@iosPetersson!我最后偷了你很多代码,但我很高兴我有机会弄清楚发生了什么。这个网站帮助我理解了tcassert手册页:http://en.wikibooks.org/wiki/Serial_Programming/termios

#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <limits>
#include <termios.h>
#include <errno.h>
#include <cassert>

using namespace std;
const int STDIN_HANDLE=fileno(stdin);
int main()
{
    string str;

    //Configuring terminal behavior
    termios tios, original;
    assert( tcgetattr(STDIN_HANDLE, &tios)==0 );
    original = tios;

    tios.c_lflag &= ~ICANON;   // Don't read a whole line at a time. 
    tios.c_cc[VTIME] = 20;   // 0.5 second timeout. 
    tios.c_cc[VMIN]  = 0;   // Read single character at a time.

    assert( tcsetattr(STDIN_HANDLE, TCSAFLUSH, &tios)==0 );

    const int size=999; //numeric_limits<streamsize>::max() turns out to be too big.
    char tmp[size];
    int res;
    cerr << "---------------STDIN_HANDLE=" << STDIN_HANDLE << endl;
    cerr << "---------------enter loop" << endl;
    while ( res=read(STDIN_HANDLE, tmp, sizeof(tmp)) ) {
        cerr << "----read: " << tmp << endl;
    }
    cerr << "--------------exit loop" << endl;

    cout << "END";
    assert( tcsetattr(STDIN_HANDLE, TCSANOW, &original)==0 );
    return 0;
}

这并不像我开始害怕那样糟糕!完美的工作!显然,所有cerr << --行都不是必需的。除了一些#include之外,我还会在完整的程序中使用它们,所以我将它们留给了我自己的目的。

嗯......无论如何它大部分都有效。只要我不使用socat将程序的stdio重定向到tcp-ip地址,它就可以正常工作。然后它给了我一个&#34;不是打字机&#34;当我试图控制一些不是tty的东西时,我猜错了。这听起来像是一个不同的问题,所以我不得不把它留在这里,我想再开始。

谢谢大家!

2 个答案:

答案 0 :(得分:1)

这里有一个关于如何进行控制台输入的快速示例(并且可以很容易地适应从另一个输入源(例如串行端口)进行输入)。

请注意,很难快速打字&#34;为了一次读取多个字符,但如果你复制粘贴,它确实会一次读取256个字符,所以假设你连接的机器确实输出了大量的字符对于东西,它应该可以正常工作来读取大块 - 我通过在一个窗口中标记一个区域来测试它,并在运行此代码的窗口中按住中键。

我添加了一些评论,但是对于完整的详细信息,您需要执行man tcsetattr - 有很多设置可能会对您有所帮助,也可能不会对您有所帮助。这被配置为读取&#34;任何&#34;的数据。如果你点击转义,它会退出(如果你按箭头键或类似物也会退出,因为那些转换为ESC-something序列,因此会触发&#34;退出&#34;功能。它&#39; ;最好不要崩溃,或设置一些处理程序来恢复终端行为,就好像你在恢复到original设置之前意外退出一样,控制台会有点奇怪。

#include <termios.h>
#include <unistd.h>
#include <cassert>
#include <iostream>

const int STDIN_HANDLE = 0;

int main()
{
    termios tios, original;
    int     status;

    status = tcgetattr(STDIN_HANDLE, &tios);
    assert(status >= 0);

    original = tios;

    // Set some input flags
    tios.c_iflag &= ~IXOFF;   // Turn off XON/XOFF... 
    tios.c_iflag &= ~INLCR;   // Don't translate NL to CR.

    // Set some output flags
    // tios.c_oflag = ... // not needed, I think. 

    // Local modes flags.
    tios.c_lflag &= ~ISIG;    // Don't signal on CTRL-C, CTRL-Z, etc.
    tios.c_lflag &= ~ICANON;   // Don't read a whole line at a time. 
    tios.c_lflag &= ~(ECHO | ECHOE | ECHOK);    // Don't show the input. 

    // Set some other parameters
    tios.c_cc[VTIME] = 5;   // 0.5 second timeout. 
    tios.c_cc[VMIN]  = 0;   // Read single character at a time.

    status = tcsetattr(STDIN_HANDLE, TCSANOW, &tios);
    assert(status >= 0);

    char buffer[256];
    int tocount = 0;

    for(;;)
    {
    int count = read(STDIN_HANDLE, buffer, sizeof(buffer));
    if (count < 0)
    {
        std::cout << "Error..." << std::endl;
        break;
    }
    if (count == 0)
    {
        // No input for VTIME * 0.1s. 
        tocount++;
        if (tocount > 5)
        {
        std::cout << "Hmmm. No input for a bit..." << std::endl;
        tocount = 0;
        }
    }
    else
    {
        tocount = 0;
        if (buffer[0]== 27)  // Escape
        {
        break;
        }
        for(int i = 0; i < count; i++)
        {
        std::cout << std::hex << (unsigned)buffer[i] << " ";
        if (!(i % 16))
        {
            std::cout << std::endl;
        }
        }

    std::cout << std::endl;
    }
    }
    status = tcsetattr(STDIN_HANDLE, TCSANOW, &original);
    return 0;
}

答案 1 :(得分:0)

如果你的仪器提供了一个流接口,并假设它在没有输入可用的情况下等待返回,我建议只使用:

cin.ignore(numeric_limits<streamsize>::max(),'\r'); // ignore everything until '\r'

另一种选择可以是使用poll,它提供了一种在一组文件描述符上多路复用(和等待)输入/输出的机制。这样做的好处是,如果您需要,可以阅读多个仪器设备。