我正在尝试为我的linux机器编写一个c ++程序,它可以与一些响应简单ascii命令的工具进行交互。我认为,我遇到的问题是一个相当普遍的请求,但我对各种论坛的搜索却没有完全相同。
我的问题是:当我连接到乐器时,由于一些通信问题,它经常会产生一堆我不想要的不同长度的数据。机器打印的数据具有行结尾' \ r'。我一直在尝试编写一个简单的循环,它将继续读取并忽略数据,直到机器静音两秒钟,然后在暴风雨结束后继续执行一些数据请求。
在搜索论坛时,我发现了关于cin.ignore
,cin.sync
,getline
和cin.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的东西时,我猜错了。这听起来像是一个不同的问题,所以我不得不把它留在这里,我想再开始。
谢谢大家!
答案 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,它提供了一种在一组文件描述符上多路复用(和等待)输入/输出的机制。这样做的好处是,如果您需要,可以阅读多个仪器设备。