Java - 应用程序在rt.exec调用WinXP 32位的c ++程序后随机挂起

时间:2013-05-28 20:32:19

标签: java windows stream block runtime.exec

您好我有一个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发送的信息,它显示其他一些查询的调试行(大约五个,带有暂停,因为外部程序需要一秒钟左右来完成300字节输出),直到它到达查询A,并且,当前,永远停在“3”。我查看代码,我认为没有理由停在3。

Gobbler是复制粘贴代码,通常是((line = br.readline())!= null)。

我在waitFor之前添加了连接,为它们添加了10000毫秒超时,只添加其中一个,注释掉了错误流,因为-rq查询无论如何都没有得到错误,添加了那些system.out.flush ,在循环时在gobbler上有一个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;
}

1 个答案:

答案 0 :(得分:0)

看看你的&#34; Main.java&#34;:

的这一行
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,因此循环永远不会终止。我认为一个一个错误是你的问题,并解释了为什么它不会每次都发生(这取决于其他程序的输出)。