您的位置:首页 > 其它

使用Process进行DOS命令交互的简单应用

2017-03-15 23:58 441 查看
继上一篇Process应用之惑后,继续在为此不断修改,后来因为需求变化,又开始了process的进步一发掘。 
    先交代下背景。第三方软件发布了命令接口,根据执行发布的命令,可以得到第三方硬件的信息。而我现在需要软件直接执行我排好序的命令,以便获取硬件信息,这时需要做个远程的命令登陆,然后远程执行命令,再退出。这其实就好比要模拟telnet、ftp等的客户端,当远程登陆后执行一个指令,然后返回一大堆执行结果,从而实现与客户端的命令交互。 
    起先,去下了个common-net.jar的源码看了看,发现telnet、ftp等通信协议都是有专门的消息通道,产生专门的端口来做通讯传输。而这个第三方的命令接口只是个在dos下能执行命令的客户端,再说,即使人家做成了类似telnet的通信协议,俺也不可能知道人家用的端口啥啥的。那现在唯一能做的是,模拟DOS窗口,进行命令的交互。 
    有了这个思路,就又想到Process可是能执行命令的,那这个是不是可以呢!Process是为了执行命令而产生的一个独立的执行线程。理论上如果只要这个线程不被销毁,那么会一直可以执行命令。可是Process三个流InputStream、OutputStream、ErrorStream在API上说的是提供输出信息的,未知获得了这输入、输出流是否能干出一番事业呢! 

1.自动执行命令的交互 
   

Java代码  


public class Demo {  

  

    public static void main(String[] args) {  

        Process process=null;  

        BufferedOutputStream out=null;  

        BufferedInputStream in=null;  

        try {  

            process=Runtime.getRuntime().exec("sqlplus ethiopia1103/ethiopia1103@db90");  

            out=new BufferedOutputStream(process.getOutputStream());  

            in=new BufferedInputStream(process.getInputStream());  

            out.write("exit".getBytes());  

            out.write("\r\n".getBytes());  

            out.flush();  

            BufferedReader br=new BufferedReader(new InputStreamReader(in));  

            String line=null;  

            while((line=br.readLine())!=null){  

                if(line.indexOf(">")!=-1) break;  

                System.out.println(line);  

            }  

        }catch (IOException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

        }finally{  

            try {  

                if(null!=out){  

                    out.close();  

                    out=null;  

                }  

                if(null!=in){  

                    in.close();  

                    in=null;  

                }  

                int value=process.waitFor();  

                if(null!=process)  

                    process.destroy();  

            } catch (IOException e) {  

                // TODO Auto-generated catch block  

                e.printStackTrace();  

            } catch (InterruptedException e) {  

                // TODO Auto-generated catch block  

                e.printStackTrace();  

            }  

        }  

    }  

}  

试试直接就退出了,证明传进去的exit命令起作用了。之所以用sqlplus做替代的命令测试,因为其和我要做的第三方接口命令类似。 
然后依据这个简单的测试封装了一个命令交互的类。直接上代码: 

Java代码  


public class DosCommandInteraction {  

  

    private static Logger logger=Logger.getLogger(DosCommandInteraction.class);  

  

    private static final String ENTER="\r\n";   //每次输入命令后回车,然后命令执行,出结果  

    private static final String END="> ";   //遇到>时就退出,证明上一个命令已经执行完  

    private static final String ERROR="ERROR";   //登录时报ERROR就证明已经登录失败  

  

    private Process process=null;  

    private BufferedOutputStream out=null;  

    private BufferedInputStream in=null;  

  

    /** 

     * 登录到该命令下,创建执行命令的环境进程 

     * @param command 登陆命令 

     */  

    public boolean loggin(String command){  

        boolean flag=true;  

        try {  

            process=Runtime.getRuntime().exec(command);  

            out=new BufferedOutputStream(process.getOutputStream());  

            in=new BufferedInputStream(process.getInputStream());  

            String result=writeCommandResult(in);   //把登录时的信息取出来,判断是否登录成功!其实也为后面能正常输出命令结果做了清理  

            String[] lines=result.split(ENTER);  

            for(String line :lines){  

                if(line.indexOf(ERROR)!=-1){  

                    flag=false;  

                    break;  

                }  

            }  

        }catch (IOException e) {  

            // TODO Auto-generated catch block  

            logger.error(e);  

            close();  

        }  

        if(!flag) close();  

        return flag;  

    }  

  

    /** 

     * 将输入的命令转化为流执行命令得到执行的记录 

     * @param command 

     * @return 

     */  

    public List<String> execCommand(String command){     

        logger.info("exec command : "+command);  

        InputStream input = new ByteArrayInputStream((command+ENTER).getBytes());  

        readerCommand(out,input);  

        String result=writeCommandResult(in);  

        logger.info(result);  

        try {  

            input.close();  

        } catch (IOException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

        }  

        return Arrays.asList(result.split(ENTER));  

    }  

  

    /** 

     * 将命令写入输出流 

     * @param outs  全局输出流 

     * @param ins   输入命令的流 

     */  

    private void readerCommand(OutputStream outs,InputStream ins){  

        int ch;  

        try {  

            while ((ch = ins.read()) != -1) {  

                outs.write(ch);  

                outs.flush();  

            }  

        } catch (IOException e) {  

            close();  

            logger.error("readerCommand",e);  

        }  

    }  

  

    /** 

     * 读取命令返回的结果 

     * @param ins 全局的输入流 

     * @return 命令结果 

     */  

    private String writeCommandResult(InputStream ins){  

        int length = -1;  

        byte[] buffer = new byte[10240];  

        String readLine = null;  

        StringBuilder readResult = new StringBuilder("");  

        try {  

            while((length=ins.read(buffer))>0){  

                readLine = new String(buffer, 0 , length,"gbk");  

                readResult.append(readLine);  

                if(readLine.indexOf(ERROR)!=-1) break;  

                if(readResult.toString().endsWith(END)||readResult.toString().endsWith(END.trim()))  

                    break;  

            }  

        } catch (IOException e) {  

            close();  

            logger.error("writeCommandResult",e);  

        }  

        return readResult.toString();  

    }  

  

    /** 

     * 所有命令执行完成后推出命令,关闭进程 

     */  

    public void quit(){  

        execCommand("quit");  

        close();  

    }  

  

    /** 

     * 关闭所有的流和进程 

     */  

    private void close(){  

        try {  

            if(null!=out){  

                out.close();  

                out=null;  

            }  

            if(null!=in){  

                in.close();  

                in=null;  

            }  

            int value=process.waitFor();  

            logger.info("process end state :" +value);  

            if(null!=process)  

                process.destroy();  

        } catch (IOException e) {  

            // TODO Auto-generated catch block  

            logger.error(e);  

        } catch (InterruptedException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

        }  

    }  

}  

我在配置文件里设置如下: 

Java代码  


<bean id="command" class="java.util.ArrayList">  

        <constructor-arg>  

            <list>  

                <value>sqlplus orcl/orcl@db</value>  

                <value>select 1 from dual;</value>  

                <value>select 2 from dual;</value>  

                <value>select 3 from dual;</value>  

                <value>select 4 from dual;</value>  

            </list>  

        </constructor-arg>  

    </bean>  

测试方法: 

Java代码  


public void handler(){  

        List<String> commList=(List<String>) SpringUtil.getObject("command");  

        logger.info("start.................");  

        DosCommandInteraction dos=new DosCommandInteraction();  

        if(!dos.loggin(commList.get(0))){  

            logger.info("connection error!");  

            return;  

        }  

        for(int i=1;i<commList.size();i++)  

            dos.execCommand(commList.get(i));  

        dos.quit();  

        logger.info("end.................");  

    }  

测试结果如下: 

Java代码  


main [2011-06-27 16:33:59] - start.................  

main [2011-06-27 16:33:59] - exec command : select 1 from dual;  

main [2011-06-27 16:33:59] -   

     1  

----------  

     1  

  

SQL>   

main [2011-06-27 16:33:59] - exec command : select 2 from dual;  

main [2011-06-27 16:33:59] -   

     2  

----------  

     2  

  

SQL>   

main [2011-06-27 16:33:59] - exec command : select 3 from dual;  

main [2011-06-27 16:33:59] -   

     3  

----------  

     3  

  

SQL>   

main [2011-06-27 16:33:59] - exec command : select 4 from dual;  

main [2011-06-27 16:33:59] -   

     4  

----------  

     4  

  

SQL>   

main [2011-06-27 16:33:59] - exec command : quit  

main [2011-06-27 16:33:59] - 从 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production  

With the Partitioning, OLAP and Data Mining options 断开  

  

main [2011-06-27 16:33:59] - process end state :0  

main [2011-06-27 16:33:59] - end.................  

真正做到了自动执行命令,并且获取到该命令的结果。 

2.如果是想直接敲命令的互动,可是尝试如下: 

Java代码  


public class TwoDemo {  

  

    public static void main(String[] args) {  

        Process process = null;  

        BufferedOutputStream out = null;  

        BufferedInputStream in = null;  

        try {  

            process = Runtime.getRuntime().exec(  

                    "sqlplus orcl/orcl@db");  

            out = new BufferedOutputStream(process.getOutputStream());  

            in = new BufferedInputStream(process.getInputStream());  

            readWrite(in, out, System.in, System.out);  //该方法借用common-net的测试例子部分的一个工具类的方法  

        } catch (IOException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

        } finally {  

            try {  

                if (null != out) {  

                    out.close();  

                    out = null;  

                }  

                if (null != in) {  

                    in.close();  

                    in = null;  

                }  

                int value = process.waitFor();  

                if (null != process)  

                    process.destroy();  

            } catch (IOException e) {  

                // TODO Auto-generated catch block  

                e.printStackTrace();  

            } catch (InterruptedException e) {  

                // TODO Auto-generated catch block  

                e.printStackTrace();  

            }  

        }  

    }  

  

    public static final void readWrite(final InputStream remoteInput,  

            final OutputStream remoteOutput, final InputStream localInput,  

            final OutputStream localOutput) {  

        Thread reader, writer;  

  

        reader = new Thread() {  

            @Override  

            public void run() {  

                int ch;  

  

                try {  

                    while (!interrupted() && (ch = localInput.read()) != -1) {  

                        remoteOutput.write(ch);  

                        remoteOutput.flush();  

                    }  

                } catch (IOException e) {  

                    // e.printStackTrace();  

                }  

            }  

        };  

  

        writer = new Thread() {  

            @Override  

            public void run() {  

                try {  

                    Util.copyStream(remoteInput, localOutput);  

                } catch (IOException e) {  

                    e.printStackTrace();  

                    System.exit(1);  

                }  

            }  

        };  

  

        writer.setPriority(Thread.currentThread().getPriority() + 1);  

  

        writer.start();  

        reader.setDaemon(true);  

        reader.start();  

  

        try {  

            writer.join();  

            reader.interrupt();  

        } catch (InterruptedException e) {  

        }  

    }  

}  

看看测试结果: 

Java代码  


SQL*Plus: Release 10.2.0.1.0 - Production on 星期一 6月 27 16:45:58 2011  

  

Copyright (c) 1982, 2005, Oracle.  All rights reserved.  

  

  

连接到:   

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production  

With the Partitioning, OLAP and Data Mining options  

  

SQL> select * from dual;  

  

DU  

--  

X  

  

SQL> select 1 from dual;  

  

     1  

----------  

     1  

  

SQL> exit  

从 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production  

With the Partitioning, OLAP and Data Mining options 断开  

和在dos下执行是完全一样的 

产生process = Runtime.getRuntime().exec()时为什么要选择这种方式呢?为什么不是ProcessBuilder了呢? 
我们现在不论使用哪种方式产生的命令执行进程都会读取进程的流,所以就不会再有流堵塞而导致无法执行下去的问题了。 
ProcessBuilder在加入命令时是以数组的形式,如果是sqlplus orcl/orcl@db就需要分为两个参数加入,而现在我们更希望是一个命令是一个字符串。 

有什么问题希望指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐