views:

212

answers:

9

Hi, I'm trying to create a Thread that keeps netsh windows command-line tool open so I can execute netsh commands without open it every single time.

The thing is, once I've created the Thread, just the first command call works... the subsequent calls seems to have no effect.

Here is my code:

public class NetshThread implements Runnable{
 private static Process netshProcess = null;
 private static BufferedInputStream netshInStream = null;
 private static BufferedOutputStream netshOutStream = null;
 public BufferedReader inPipe = null;

 public void run(){
  startNetsh();
 }

 public void startNetsh(){
  try {
   netshProcess = Runtime.getRuntime().exec("netsh");
   netshInStream = new BufferedInputStream(netshProcess.getInputStream());
   netshOutStream =  new BufferedOutputStream(netshProcess.getOutputStream());
   inPipe = new BufferedReader(new InputStreamReader(netshInStream));
  } catch (IOException e) {
   e.printStackTrace();
  }
 } 

 public void executeCommand(String command){
  System.out.println("Executing: " + command);
  try {
   String str = "";
   netshOutStream.write(command.getBytes());
   netshOutStream.close();
   while ((str = inPipe.readLine()) != null) {
                System.out.println(str);
            }
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 public void closeNetsh(){
  executeCommand("exit");
 }

 public static void main(String[] args){
  NetshThread nthread = new NetshThread();
  nthread.run();
  String command = "int ip set address " +
    "\"Local Area Connection 6\" static .69.69.69 255.255.255.0";
  nthread.executeCommand(command);
  command = "int ip set address " +
    "\"Local Area Connection 6\" static 69.69.69.69 255.255.255.0";
  nthread.executeCommand(command);
  System.out.println("*** DONE ***");
 }
}

Thank you!!! =)

+3  A: 

You are closing the output stream.

Jonathan Feinberg
even removing that .close... it wont work =S
Valentina
A: 

You do definitely need to remove the close, else you'll never be able to execute another command. When you say "it won't work" once the close() call removed, do you mean no commands are processed?

Chances are that after you send the bytes for the command, you need to send some kind of confirmation key for the process to start, well, processing it. If you'd normally enter this from the keyboard it might be as simple as a carriage return, otherwise it might need to be a Ctrl-D or similar.

I'd try replacing the close() line with

netshOutStream.write('\n');

and see if that works. Depending on the software you might need to change the character(s) you send to signify the end of the command, but this general approach should see you through.

EDIT:

It would also be prudent to call

netshOutStream.flush();

after the above lines; without the flush there's no guarantee that your data will be written and in fact, since you're using a BufferedInputStream I'm 99% sure that nothing will be written until the stream is flushed. Hence why the code afterwards blocks, as you're waiting for a response while the process has not seen any input yet either and is waiting for you to send it some.

Andrzej Doyle
Thank you! buuuut... I replaced the .close line with the .write('\n') and the while loop located right after the .write('\n') seems to get stuck forever =S....
Valentina
And after removing the close() call, it executes the 1st command, it shows me its output but it never leaves the while loop, and that's it, not other thing it's executed.
Valentina
I'd just changed my code to: PrintWriter netshWriter = new PrintWriter(netshOutputStream, true); // auto-flush writernetshWriter.println(command);so I don't have to worry about flushing the stream ... It executes the first command, shows me some output and it gets block in the while loop, and then, nothing else happens =S
Valentina
A: 

I'd try:

PrintWriter netshWriter = new PrintWriter(netshOutputStream, true); // auto-flush writer

netshWriter.println(command);

No close()ing the stream, flush the stream automatically, and uses a writer to send character data rather than relying on the platforms "native character set".

Mr. Shiny and New
Hi !!!... I tried ur solution, and same thing... it got stuck on: while ((str = inPipe.readLine()) != null) { System.out.println(str); }
Valentina
+1  A: 

This seems wrong in many ways.

First, why a Runnable object? This isn't ever passed to a Thread anywhere. The only thread you're creating isn't a java thread, it is an OS process created by exec().

Second, you need a way to know when netsh is done. Your loop that reads the output of netsh will just run forever because readLine will only return null when netsh closes its standard out (which is never, in your case). You need to look for some standard thing that netsh prints when it is done processing your request.

And as others mentioned, close is bad. Use a flush. And hope netsh uses a flush back to you...

Keith Randall
+2  A: 

You need to move the stream processing into separate threads. What's happening is that inPipe.readLine() is blocking waiting for netsh to return data. Apache has a package that deals with process handling. I'd look at using that instead of rolling your own (http://commons.apache.org/exec/)

Chris Gow
A: 

Ok... I'm now using a PrintWriter instead... so I think I don't need to flush anything anymore, since the constructor is:

new PrintWriter(netshOutStream, true); (just like Mr. Shiny told me)...

Suppose I decide to break the while loop when the first output line is available... I doesn't work either... the next command wont be executed.... My code now looks like:

import java.io.*;

public class NetshThread implements Runnable{
    private static Process netshProcess = null;
    private static BufferedInputStream netshInStream = null;
    private static BufferedOutputStream netshOutStream = null;
    public BufferedReader inPipe = null;
    private PrintWriter netshWriter = null;

    public void run(){
     startNetsh();  
    }

    public void startNetsh(){
     try {
      netshProcess = Runtime.getRuntime().exec("netsh");
      netshInStream = new BufferedInputStream(netshProcess.getInputStream());
      netshOutStream =  new BufferedOutputStream(netshProcess.getOutputStream());
      netshWriter = new PrintWriter(netshOutStream, true);
      inPipe = new BufferedReader(new InputStreamReader(netshInStream));
     } catch (IOException e) {
      e.printStackTrace();
     }
    } 

    public void executeCommand(String command){
     System.out.println("Executing: " + command);
     try {
      String str = "";
      netshWriter.println(command);
      while ((str = inPipe.readLine()) != null) {
                System.out.println(str);
                break;
            }
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
    public void closeNetsh(){
     executeCommand("exit");
    }

    public static void main(String[] args){  
     NetshThread nthread = new NetshThread();
     Thread xs = new Thread(nthread);
     xs.run();
     String command = "int ip set address " +
       "\"Local Area Connection 6\" static .69.69.69 255.255.255.0";
     nthread.executeCommand(command);
     command = "int ip set address " +
       "\"Local Area Connection 6\" static 69.69.69.69 255.255.255.0";
     nthread.executeCommand(command);
     System.out.println("*** DONE ***");
    }
}

and the output I get:

Executing: int ip set address "Local Area Connection 6" static .69.69.69 255.255.255.0 netsh>.69.69.69 is not an acceptable value for addr. Executing: int ip set address "Local Area Connection 6" static 69.69.69.69

Why the second command is not executed???

255.255.255.0

* DONE *

Valentina
I believe its because readLine() is blocking waiting for more input from the command. See my earlier answer
Chris Gow
You don't want to actually make a java Thread - that's likely to cause problems (calling executeCommand before startNetsh is finished).You need to read all of (and only all of) the output of netsh before you send it the next command. If you only read one line, and it is trying to write more than one line to you, then it might be waiting in a write() call and won't pick up your next command.
Keith Randall
A: 

I've used scanner instead of BufferedReader, just because I like it. So this code works:

Scanner fi = new Scanner(netshProcess.getInputStream());


public void executeCommand(String command) {
 System.out.println("Executing: " + command);
 String str = "";
 netshWriter.println(command);
 fi.skip("\\s*");
 str = fi.nextLine();
 System.out.println(str);
}

It executes both commands.

tulskiy
THAAAAAAAAAAAAAAAAAAANK YOUUUUUUUUUUUUUUUUUUUU !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!=)I LOVE YOU!
Valentina
I got used to the fact that most users here are male, so last sentence was kinda shocking before I read your name :) Good luck, Valentina. BTW, are you Russian?
tulskiy
A: 

LOL Piligrim ... yes, I'm a girl =) ... and nop... I'm venezuelan... !!!

Valentina
A: 

Hi, it´s me again....

Everything seemed to work just fine until a teacher tried my app in a spanish-windows enviroment....

my code looks like this:

Scanner fi = new Scanner(netshProcess.getInputStream());

public void executeCommand(String command) {
        System.out.println("Executing: " + command);
        String str = "";
        netshWriter.println(command);
        fi.skip("\\s*");
        str = fi.nextLine();
        System.out.println(str);
}

and what i need is to somehow set the netshWriter encoding to the windows default.

Can anyone know who to do this?

Thank you!!!

Valentina