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

标签 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 程序作为中介。

对于每一种类型的查询我都有一个函数,有很多类型的查询,但是每个函数的代码都差不多,只有十六进制字符串查询和我在最终输出中查找的字符串变化,查询到设备不是并行运行,程序应该按顺序运行。 (当前)代码如下:

主.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;
    }
}

如您所见,我正在使用打印调试,因为生产电脑(带有外部设备)没有调试工具并且距离很远。我使用 *.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 的运行方法的开始和结束处打印,两者似乎都很好地开始和结束。

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

关于Java - 在 rt.exec 调用 WinXP 32 位的 C++ 程序后,应用程序随机挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16800971/

相关文章:

java - 从 jformatted 文本字段中获取浮点值

java - 我的任务是创建一个 Java 应用程序,该应用程序使用 2 个同步线程来计算每月利息并更新帐户余额

.net - 7 个 64 位操作系统上带有 32 位 oracle 客户端驱动程序的 System.data.OracleClient

windows - 在 Windows 中通过命令行启动没有菜单/地址栏的 IE

c++ - 将 C++ 流用于 cout 或文本文件

java - 如何在解析不正确的字符串时获得异常或任何类型的反馈

java - 我可以使用 java.awt.FileDialog 只允许用户选择文件夹吗

Java:并行过滤大文本文件,同时保持顺序

c++ - 如何在 Windows 中编写自己的 'filesystem'?

node.js - 在客户端连接关闭时中止 ReadStream