`
天泪不死
  • 浏览: 27960 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

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

1.自动执行命令的交互
   
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做替代的命令测试,因为其和我要做的第三方接口命令类似。
然后依据这个简单的测试封装了一个命令交互的类。直接上代码:
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();
		}
	}
}

我在配置文件里设置如下:
<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>

测试方法:
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.................");
	}

测试结果如下:
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.如果是想直接敲命令的互动,可是尝试如下:
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) {
		}
	}
}

看看测试结果:
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就需要分为两个参数加入,而现在我们更希望是一个命令是一个字符串。



有什么问题希望指正。
分享到:
评论

相关推荐

    C#调用DOS命令。Process类的用法

    在.NET框架中,C#提供了一种方便的方式来与操作系统交互,包括执行DOS命令,这就是通过使用`System.Diagnostics.Process`类。本篇文章将详细介绍如何利用`Process`类在C#中调用DOS命令,以及相关的核心概念和步骤。 ...

    C#模拟Dos命令

    这些文件可能包含了如何使用C#来模拟DOS命令,比如执行ping(ICMP协议的命令)或其他网络相关的命令的实例。 8. **学习和调试**: 对于初学者,可以通过打开`ICMP_App.sln`在Visual Studio中查看和运行项目,理解...

    C#执行dos命令

    首先,执行DOS命令的核心在于使用`System.Diagnostics.Process`类。这个类提供了启动外部进程、与之通信以及控制其生命周期的能力。在C#中,我们可以通过以下方式创建并执行一个DOS命令: ```csharp using System....

    Java执行dos命令

    在Java编程中,有时我们需要与操作系统进行交互,执行一些DOS命令,比如创建文件、删除文件、拷贝文件等。这种需求通常是通过Java的Runtime类或者ProcessBuilder类来实现的。下面将详细介绍如何使用Java执行DOS命令...

    调用DOS命令的例子,详细源码

    1. **使用System.Diagnostics命名空间**:在C#中,我们可以利用`System.Diagnostics`命名空间中的`Process`类来启动外部程序,包括执行DOS命令。 2. **创建Process对象**:首先,创建一个`Process`对象,然后设置它...

    vc调用dos命令总结

    总之,VC调用DOS命令是通过C++程序与操作系统进行交互的一个重要手段,它允许开发者在C++环境中执行各种系统级操作,增强了程序的功能性和灵活性。而“windows补丁安装器”则是一个实际应用案例,展示了这种技术在...

    执行DOS命令 c#

    下面将详细阐述如何在C#中执行DOS命令以及相关的知识点。 首先,导入System.Diagnostics命名空间,这是执行DOS命令的基础: ```csharp using System.Diagnostics; ``` 然后,创建一个ProcessStartInfo对象,设置...

    c#执行DOS命令

    总结起来,C#执行DOS命令主要涉及`System.Diagnostics.Process`类的使用,包括设定命令、处理命令执行后的退出行为以及重定向输出。掌握这一技巧,对于编写需要与操作系统底层交互的应用程序是非常有用的。

    java调用DOS命令

    以上就是关于Java调用DOS命令的基本知识,通过这些技术,开发者可以在Java程序中灵活地与操作系统交互,执行各种系统级任务。在实际应用中,可以根据具体需求选择Runtime或ProcessBuilder,并确保正确处理命令输出和...

    C#中利用process类调用外部程序以及执行dos命令

    通过这个类,我们可以启动、控制和管理应用程序,甚至可以执行DOS命令。以下将详细阐述如何利用`Process`类来调用外部程序并执行DOS命令。 1. **创建Process对象** 在C#代码中,首先需要实例化一个`Process`对象,...

    DELPHI在视窗里执行DOS命令并返回结果.rar

    DELPHI在Windows环境下执行DOS命令并获取返回结果是一个常见的需求,这通常涉及到系统交互和进程控制。在Delphi编程中,我们可以使用内置的`ShellExecute`函数或者通过创建进程对象来实现这一功能。本项目提供的代码...

    c#winform运行DOS指令,隐藏命令窗口

    总之,通过使用`System.Diagnostics.Process`类,我们可以方便地在C# WinForm应用中执行DOS命令,并通过设置`ProcessStartInfo`的属性来隐藏命令窗口,提供用户友好的体验。这个功能在很多自动化和脚本执行场景中...

    DOS命令_CallingDOScomman_labview调用Dos_labview_sixzk3_

    在Windows操作系统中,DOS命令(也称为命令行接口或命令提示符命令)是一种与操作系统交互的方式,允许用户执行各种任务,如创建、删除文件,查看目录结构,以及运行可执行程序等。 描述"Labview通过调用Dos命令,...

    取DOS命令返回结果

    了解如何获取DOS命令的返回结果对于进行自动化脚本编写、系统管理和故障排查至关重要。 标题"取DOS命令返回结果"指的是通过编程或脚本方式调用DOS命令,并获取该命令执行后的输出信息。在Windows系统中,这通常涉及...

    QT5 编写小例子 调用外部Dos 命令

    在QT5中,我们可以通过QProcess类来调用外部的系统命令,比如DOS命令,实现与操作系统进行交互。这个小例子展示了如何在QT5环境中使用QProcess来执行像`ipconfig`和`ping`这样的命令,不仅限于Windows,也适用于...

    java 调用 dos 命令

    例如,我们可以使用`Runtime.getRuntime().exec(command)`方法来执行DOS命令。这里的`command`字符串就是你要执行的DOS命令。这种方法简洁明了,适用于简单的命令执行,但它的缺点在于处理命令输出和错误流时不够...

    C#程序中直接调用dos命令操作

    其中,C#能够直接调用DOS命令(亦称CMD命令)进行系统级操作,这为开发者提供了一种高效、灵活的方式来执行特定任务,如文件管理、网络诊断、系统配置等。本文将深入探讨如何在C#程序中直接调用DOS命令,并通过示例...

    Java执行DOS命令

    本文将深入探讨如何使用Java执行DOS命令,并给出具体示例。 首先,`Runtime`类是每个Java应用程序都有的一个实例,它允许程序与正在执行它的环境进行交互。我们可以通过`Runtime.getRuntime().exec()`方法来执行DOS...

    C#调用DOS命令方法

    C#中调用DOS命令主要通过`System.Diagnostics.Process`类实现,该类提供了启动、控制和监视外部应用程序的功能。下面详细介绍几种常见方法: #### 方法一:使用`Process`类直接调用命令行程序 这是最直接的方法,...

    VC运行DOS命令源代码

    在VC(Visual C++)环境下,我们经常需要与操作系统进行交互,执行一些系统级别的操作,例如运行DOS命令。这个“VC运行DOS命令源代码”示例就是为了解决这样的需求,它允许开发者在VC程序中调用并执行DOS命令。下面...

Global site tag (gtag.js) - Google Analytics