你好,我有一个visual studio 2008 c++项目,通过COM1与自定义设备通信。测试表明它工作如预期(当从cmd.exe中使用时),它发送一些数据(通过args发送给它)并打印(cout)它从端口读取的下一个300字节。
的例子:
cppprogram.exe -send RANDOM_HEXSTRING_HERE -C COM1[0000FFABCD1873295287210173983198396918273(…)1278612851FFEB]
回复格式始终为[hexstring]。如果出现错误,则返回-1,否则返回0。当在cmd.exe上执行时,您可以看到它"缓慢"打印,大约100字节,一秒钟等待,另一个100,等等,这取决于外部设备生成数据的速度。但是它总是结束,因为设备总是在打印,程序只等待300字节。
为了构建在这个"系统"之上,我正在用Java编写一个程序。它应该向设备发送一个又一个查询,并处理输出。我使用cpp程序作为中介。
对于每种类型的查询,我都有一个函数,有许多类型的查询,但是每个函数的代码是相似的,只有十六进制字符串查询和我在最终输出中寻找的字符串发生了变化,对设备的查询不是并行运行的,程序应该顺序运行。(当前)代码如下:
Main.java
main()
{
(...)
while( keepgoing )
{
(...)
print( start Query A )
QueryDeviceA()
print( end Query A )
(...)
}
(...)
}
public String QueryDeviceA()
{
try
{
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec( "cppprogram.exe -C COM1 -rq" ); //rq performs the query A without having to put the hexstring
// any error message?
// StreamGobbleAndReturnAsString errorGobbler = new StreamGobbleAndReturnAsString( pr.getErrorStream(), "ERR" );
// any output?
StreamGobbleAndReturnAsString outputGobbler = new StreamGobbleAndReturnAsString( pr.getInputStream(), "OUT" );
// kick them off
System.out.println( "1" );
System.out.flush();
outputGobbler.start();
// errorGobbler.start();
int exitVal = pr.waitFor();
outputGobbler.join();
// errorGobbler.join();
System.out.flush();
System.out.println( "2" );
String returnValue = outputGobbler.getReturnValue();
rt.gc();
System.out.println( "3" );
if( returnValue == null ) return null;
int start = returnValue.indexOf("[");
int end = returnValue.indexOf("]", start);
boolean datafound = false;
if( start > -1 && end > -1 )
{
String returnpart = returnValue.substring(start+1, end);
if( returnpart == null ) return null;
start = 0;
while( start < returnpart.length() )
{
do { start = returnpart.indexOf("0103", start); } while( start % 2 > 0 && start != -1 );
if( start == -1 ) break;
start+=2;
do { end = returnpart.indexOf("04", start); } while( end % 2 > 0 && end != -1 );
if( end == -1 ) break;
System.out.println( "4" );
returnValue = TranslateEscapedData(returnpart.substring(start, end)); //doesnt have infinite loops
System.out.println( "5" );
if( returnValue.length() != 30 ) continue;
if( !"040F20".equals( returnValue.substring(12,18) ) ) continue;
System.out.println( "6" );
//Verify Checksum
if( !ValidChecksum(returnValue) ) continue; //doesnt have infinite loops
System.out.println( "7" );
returnpart = returnValue.substring(18,26);
datafound = true;
break;
}
if( !datafound ) return null;
return returnpart;
}
return null;
}
catch( Exception e )
{
System.out.println(e.toString());
e.printStackTrace();
}
return null;
}
StreamGobbler.java
public class StreamGobbler extends Thread
{
public InputStream is;
public String type;
public OutputStream os;
private StreamGobbler()
{
}
public StreamGobbler(InputStream is, String type)
{
this(is, type, null);
}
public StreamGobbler(InputStream is, String type, OutputStream redirect)
{
this.is = is;
this.type = type;
this.os = redirect;
}
@Override
public void run()
{
try
{
PrintWriter pw = null;
if( os != null ) pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while( (line = br.readLine()) != null )
{
if( pw != null ) pw.println(line);
//System.out.println( type + ">" + line );
}
if( pw != null ) pw.flush();
}
catch( IOException ioe )
{
ioe.printStackTrace();
}
}
}
StreamGobbleAndReturnAsString.java
public class StreamGobbleAndReturnAsString extends util.StreamGobbler
{
private String returnValue;
public StreamGobbleAndReturnAsString(InputStream is, String type)
{
this(is, type, null);
}
public StreamGobbleAndReturnAsString(InputStream is, String type, OutputStream redirect)
{
super( is, type, redirect );
}
@Override
public void run()
{
try
{
PrintWriter pw = null;
if( os != null ) pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while( (line = br.readLine()) != null )
{
if( pw != null ) pw.println(line);
//System.out.println( type + ">" + line );
returnValue += line;
}
if( pw != null ) pw.flush();
//br.close();
}
catch( IOException ioe )
{
ioe.printStackTrace();
}
}
/**
* @return the returnValue
*/
public String getReturnValue() {
return returnValue;
}
/**
* @param returnValue the returnValue to set
*/
public void setReturnValue(String returnValue) {
this.returnValue = returnValue;
}
}
正如你所看到的,我正在使用打印调试,因为生产pc(带有外部设备)没有调试工具,而且距离很远。我使用*.bat文件执行这个java程序,并将其拖放到打开的cmd.exe窗口中,它开始显示通过System.out发送的信息。println,它将显示其他几个查询的调试行(大约5行,由于外部程序需要一秒钟左右的时间来完成300字节的输出,因此会暂停),直到它到达查询a,并且目前永远停止在"3"处。我看了看代码,没有理由在3处停下来。
Gobbler是复制粘贴的代码,它是通常的while((line = br.readline()) != null)。
我把连接放在waitFor之前,为它们添加了10000毫秒超时,只是其中一个,注释掉错误流,因为-rq查询无论如何都没有得到错误,添加了那些system.out。Flush,在gobler while循环中有一个system.out.println(行)。它只改变调试行,然后永远挂起或其他一些对我来说更合乎逻辑的错误。如。如果我注释掉线程连接,我通常会得到完整的输出,但有时它并不完整,我认为这是因为我在完成工作之前读取了gobbler的结果,这就是我添加连接的原因。
当我在gobbler的循环中使用system.out.println时,挂起似乎出现在较早的查询上,所以我唯一的线索是在那里,但这显然超出了我目前的知识,所以这里的问题:)我在两个gobbler的运行方法的开始和结束处放置了一个打印,并且两者似乎都开始和结束得很好。
代码目前在java 1.6.0_23-b05, Windows XP SP 2上运行,生产机器上的配置实际上是随机的,超出了我的范围,但如果它与它们相关,我可以添加那个注释并耸耸肩,我猜。
编辑:流阅读器的工作只是有一些有用的…
public String Query()
{
try
{
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec( "cppprogram.exe -C COM1 -rq" );
// any error message?
StreamGobbleAndReturnAsString errorGobbler = new StreamGobbleAndReturnAsString( pr.getErrorStream(), "ERR" );
// any output?
StreamGobbleAndReturnAsString outputGobbler = new StreamGobbleAndReturnAsString( pr.getInputStream(), "OUT" );
// kick them off
outputGobbler.start();
errorGobbler.start();
int exitVal = pr.waitFor();
outputGobbler.join();
errorGobbler.join();
String returnValue = outputGobbler.getReturnValue();
rt.gc();
if( exitVal == 0 ) //success
{}
else //cppprogram.exe returned error, do we care?
{}
if( returnValue == null ) return null;
//process returnValue further if needed and then
return returnValue;
}
catch( Exception e )
{
System.out.println(e.toString());
e.printStackTrace();
}
return null;
}
看看你的"Main.java"中的这一行:
do { start = returnpart.indexOf("0103", start); } while( start % 2 > 0 && start != -1 );
假设有一个像
这样的字符串returnpart = "x0103";
第一次调用
returnpart.indexOf("0103", start);
, start
= 1。start % 2
为1,start
为1,循环继续。
现在我们进行调用,并且得到start
仍然等于1,因此循环将永远不会终止。我认为偏差是你的问题,并解释了为什么它不是每次都发生(它取决于其他程序的输出)。