您好,我有一个 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 程序作为中介。
对于每种类型的查询我都有一个函数,有很多类型的查询,但是每个函数的代码都是相似的,只有十六进制字符串查询和我在最终输出中查找的字符串发生了变化,对设备的查询没有运行并行,程序应该按顺序运行。(当前)代码如下:
主.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 发送的信息,它显示其他一些查询的调试行(大约五个,与暂停,因为外部程序需要一秒钟左右才能完成 300 字节的输出),直到它到达查询 A,并且目前永远停止在“3”。我查看了代码,我认为没有理由停在 3 处。
Gobbler 是复制粘贴的代码,它通常是 while( ( line = br.readline() ) != null )。
我已经将连接放在waitFor之前,向其中一个添加了10000毫秒超时,注释掉了错误流,因为-rq查询无论如何都没有出错,添加了那些system.out.flush,有一个在 gobbler while 循环上的 system.out.println(line)。而且它只会更改在永远挂起之前打印的调试行或其他一些对我来说似乎更合乎逻辑的错误。例如。如果我注释掉线程连接,我通常会得到完整的输出,但有时它并不完整,我假设是因为我在 gobbler 完成工作之前读取它的结果,这就是我添加连接的原因。
当我在 gobbler 的循环中使用 system.out.println 时,挂起似乎出现在较早的查询中,所以我唯一的线索就在那里,但这显然超出了我目前的知识范围,所以这里的问题:) 我在两个 gobblers 的 run 方法的开始和结束,并且似乎都很好地开始和结束。
该代码当前在 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;
}