I am trying to read/write values from/to telnet process by means of ProcessBuilder.
public static void main(String[] args) {
try {
telnetProcess = new ProcessBuilder("C:\\Windows\\System32\\telnet.exe","x.x.x.x").start();
telnetInputReader = new BufferedReader(new InputStreamReader(telnetProcess.getInputStream()));
telnetOuputWriter = new BufferedWriter(new OutputStreamWriter(telnetProcess.getOutputStream()));
expectPattern("login:");
sendCmd("user");
expectPattern("password:");
sendCmd("pwd");
expectPattern("switch>#");
sendCmd("exit");
expectPattern("Connection to host lost");
} catch (IOException ex) {
System.out.println("Exception : " + ex);
}
}
I got the following error
java.io.IOException: Cannot run program "C:\Windows\System32\telnet.exe": CreateProcess error=2, The system cannot find the file specified
I tried to change the file path to unix formatted style like C:/Windows/System32/telnet.exe and no luck. (Though I expected it to not to work). Then copied the telnet.exe from it's location to some other user's home directory and I was not getting any errors. (???)
But, I didn't see the output as expected. I didn't get any response from the process and the code exited.
public static void sendCmd(String cmd) {
System.out.println(cmd);
try {
telnetOuputWriter.write(cmd + "\n", 0, cmd.length());
} catch (IOException ex) {
Logger.getLogger(TelnetProcessHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static String expectPattern(String pattern) {
String cmdResponse = "";
try {
String line = "";
// Always getting 'null' here
while ((line = telnetInputReader.readLine()) != null) {
System.out.println(line);
cmdResponse += line;
if (line.contains(pattern)) {
break;
}
}
} catch (IOException ex) {
System.out.println("ex : " + ex);
}
return cmdResponse;
}
What is wrong in this ? Then, one other query. I have tried using PrintWriter for writing to process which in turn has BufferedWriter in it, like,
telnetOuputWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(telnetProcess.getOutputStream())));
Is this fine to use PrintWriter in this context ?
Note : Due to some reasons, I would like to stick with using telnet by means of process, not with Socket or TelnetClient or expect4j.
The telnet program does not use the standard input and output streams to communicate with the user, it needs to use the console device directly. You'll have to find an alternative way of doing what you're trying to do.
For example you could use a Java library that implements the telnet protocol. See this question for example: Open source Telnet Java API
I am creating a wrapper for a executable that runs on the windows command line. The executable takes a few commands then attempts to connect to another device. then it outputs and ERROR! or Ready For "Device Name" i do not get this message until the app exits. The problem is this app is a tunnel allowing me to run telnet on the external box but i need to make sure the Device is ready this is my code.
public void startUDPTunnel() {
//TODO Pull Amino serial number from webportal
Properties prop = new Properties();
InputStream inConfig = getClass().getClassLoader().getResourceAsStream("config.properties");
try {
prop.load(inConfig);
} catch (IOException e) {
System.out.println(e.getMessage());
}
String server = prop.getProperty("server");//config.GetProp("server");
System.out.println(server);
String port = prop.getProperty("port");//config.GetProp("port");
System.out.println(port);
String location = prop.getProperty("location");//config.GetProp("location");
System.out.println(location);
String url = prop.getProperty("URL");
System.out.println(url);
String input = "";
try {
input = getSerial(url);
System.out.println(input);
Process p = Runtime.getRuntime().exec(location+"udptunnel.exe -c 127.0.0.1 23 "+input+" "+server+" "+port+" 127.0.0.1 23");
threadSleep();
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
if(line.equals("ERROR!")){
System.out.println("There was an ERROR");
}
if(line.equals("Ready for \""+input+"\"")){
System.out.println("Load Telnet");
}
}
p.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
Sorry there is a lot of debug code left in this function.
EDIT
OK I am pretty sure know what the issue is bufferReader.readLine() requires a \n or \r or just hangs is there anyway to watch the stream with out the buffer?
You should use a ProcessBuilder, and then use redirectErrorStream(). I think this will cause stdout of the process to be unbuffered. And even if it doesn't, you'll only have to read from one InputStream to get both stdout and stderr.
I have figured out my problem the applications that i am executing with java do not have a EOL at the end of the line in fact they just hang on the line For example telnet waits for the username then the password. i am not sure this is proper but it works and is what i am going to use for now
while((i=br.read())!=-1){
ch += (char)i;
}
This outputs every char as they come in when then i just make sure the string contains what i am looking for!
I am making a game with LibGDX, now I am trying to restart the game by re-running the jar, for that I am using the jar's path, finding it by using:
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString().replace("%20", " ");
After using that I attempt to restart using a Process and the Runtime.getRuntime().exec("java -jar " + location + "\\Test.jar");
Now that far it works, but the problem is that the first instance of the game from which I create the new instance (from which I restart), remains on the screen and won't close until the second instance closes.
This is my code for the restart:
public static void restart() {
Gdx.app.exit();
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString().replace("%20", " ");
System.out.println(location);
Process pro = Runtime.getRuntime().exec(
"java -jar " + location + "\\Test.jar");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
"reprot.txt")));
InputStream stream = pro.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream));
String line = "";
writer.write(location);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Am I doing something wrong? How can I close the first instance of the game after starting the second instance?
I tried doing it using a different thread, having this code:
public static void main(String[] args) {
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString();
System.out.println(location);
Process pro = Runtime.getRuntime().exec(
"java -jar " + location + "\\Test.jar");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
"report.txt")));
InputStream stream = pro.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream));
String line = "";
writer.write(location);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
But it still has the same problem.
EDIT: I tried to used System.exit(0);, and try to use the LwjglApplication to close it but it remains the same, however I have made some progress:
When creating this new process, the second instance of the game, the first instance's UI freezes, causing the game not to respond. I thought, well if it doesn't respond I should just find a way to kill it off and leave the other instance, but that can't be accomplished due to the fact that when closing once instance of the game (by forcing a close on it), you close both instances.
I think I figured out a piece of this annoying puzzle:
Let's say our main instance of the game is called 'Game_1', and the instance that we're creating is 'Game_2'.
After looking at the code and thinking about what happens (with testing of small classes and not the large game), I think that that the 'Game_1' isn't closing because 'Game_2' isn't closing.
In more complex terms, the instance of 'Game_1' won't close because it is somehow attached to 'Game_2' and thus is waiting for 'Game_2' to close before it itself will close.
So if that correct, the way to close 'Game_1' would to make 'Game_2' run simultaneously to 'Game_1' making it independent and thus allowing 'Game_1' to continue with the current progress of the code, which will be the implementation of Gdx.app.exit(); method.
So now the question remains, how do I make the instance of 'Game_2' run independently from 'Game_1'? Or how would I make 'Game_1' continue the code or, not to wait till an exit value will be received from 'Game_2'.
EDIT2: MASSIVE PROGRESS After adding a line of code System.exit(0); in the restart class, 'Game_1' continued not to respond, BUT after terminating 'Game_1', 'Game_2' did not get turned off, I'll continue to play around with it until I figure out what to do.
EDIT3: I continue to try and fix it so it'll work, but have ran into another problem. I figured out that if I can simulate an exit value for the process of 'Game_2' without actually exiting, I can terminate 'Game_1' 's UI, while keeping game 2 still alive, if anyone has any ideas please share them with me.
EDIT4: I continue my attempts to do this, but I can't follow what's going on, I'm trying to pass a PID to the restart class by writing
"java -cp " + location + "\\Test.jar Restart " + PID but it doesn't seem to work, or I don't seem to receive any information (syso for example) from the Restart class. On top of that I have found a memory leak inside my game that I will address once I finish working this out.
Please, if you have any idea how to help me, even just a theory, please share it.
EDIT5: I have established the efficiency of the termination of a given process using this LINK
Here is the solution, since I can't answer my problem until tomorrow:
Alright, finally, I finished solving it, it has a few problems, only two of them I will mention since it concerns the code in general and not how I'm using it. 'Game_1' will be the game that was started first, and 'Game_2' will be the instance of the restarted game. This is it:
First off I got the PID of the current process that is currently running, 'Game_1', from which I will create 'Game_2'. The problem with this is that Java applications all have the same name, 'Java.exe', and what that causes is a bunch of applications of the same name, so for now I add a message saying that the game should be the only java instance on the computer, not eclipse, or anything like that.
The code for the PID retrieval is this:
private static String getPID() {
try {
String line;
Process p = Runtime.getRuntime().exec(
System.getenv("windir") + "\\system32\\" + "tasklist.exe");
BufferedReader input = new BufferedReader(new InputStreamReader(
p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
if (line.contains("java")) {
String data = line.subSequence(27, 35).toString();
data = data.trim();
return data;
}
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}
return "-1";
}
Now, later on, I will look for a way to name the process that is currently running, so that you won't have to use line.contains("java") since it might give more than one instance, but for now it's as good as it gets.
This code uses an exe file inside of windows that basically gives all the current processes running on the computer, so you can find your.
The returned list is given in this format:
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
All the processes will be located here.
The PID is located between the 27th character to the 35th, and that's why I added
String data = line.subSequence(27, 35).toString();
so that it returns the PID of the process.
After doing that I prepared a cmd with an execution command as follows:
String jarLocation = new File(YourClass.class.getProtectedDomain().getCodeSource().getLocation().getPath()).toString();
String command = "java -cp " + jarLocation + " your.Package.here.Restart \""+PID+"\"";
Runtime.getRuntime().exec("cmd /C start cmd.exe /C \"" + command + "\"");
Now first off I got the location of the .jar file. It is returned in the following format:
C:\A%20Folder\To%20YourJar\YourJar.jar
So there needs to be the following formatting to the location
jarLocation = jarLocation.replace("%20", " ");
Just to turn all the %20's to white spaces.
Note If you do not have spaces in your directory the previous step of formatting is not required.
After that I had prepared the actual command, which is as follows (this is for me, but you can change it to fit your needs).
java - calling the java program in cmd.
-cp - execute a class located inside of a jar file. Then I added the jar location, then added the package and added an argument (for the String[] args in the main method) of the PID to be terminated.
Now the following line of code represents a OS dependency, so if you want to add multiple OS support, I would recommend finding the equivalent to cmd in the other OS and figuring out how to use it.
The last line of code is the execution, where we get the runtime, start a cmd and execute a single command before closing the cmd.
You can find details about it in the following issue: LINK
#Vincent Ramdhanie also gives a link to commands you can run using runtime when activating cmd.
After that I had a class that was actually restarting the game itself, which is named Restart.
Like the last line of code, a line of code there represents OS dependency, so if you want to support multiple OS's, find the equivalent to taskkil in other OS's. According to #erhun it's pkill for Linux or something, sorry I don't exactly remember.
This is the code for that class:
public static void main(String[] args) {
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString();
location = "\"" + location.replaceAll("%20", " ");
Runtime.getRuntime().exec("taskkill /F /PID " + args[0]);
Runtime.getRuntime().exec("java -jar " + location);
} catch (IOException e) {
e.printStackTrace();
}
}
Like with the previous line, location here means the same thing as before, and you have to format it if you have spaces in the directory.
After that you need to terminate the previous process, that is where taskkill /F /PID + args[0] comes in. If you run that you will terminate the task with the id of args[0], which was 'Game_1' 's PID.
After that I just run the jar file and you're good to go.
I would like to note something, I tried running it so that the main class (DesktopLauncher) would use the Restart class through an exec command in runtime, but the problem presisted, and I found that the only way to fix this, was to work around it, and use cmd. (This was after using cmd to debug the location string).
That's it, I worked a whole week, trying to fix this problem, and as crude as this is, it's a solution, for the mean time. If I have a problem somewhere in this code please tell me.
There is a much 'easier' method to do what you want. You will of course have to adapt to your own application as what you are trying to do is completely outside of libgdx's scope. It is a cross-platform library and the idea update/restart is very different with mobile.
An actual desktop cross-platform solution can be found here, I would highly suggest you not use your method as it is not a reliable solution and very platform specific.
Below is an example of how you would do it in libgdx. You need two things, code to launch the application and code to restart it.
Launcher:
public class TestLauncher {
public static void main(final String[] args) {
final LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "Game";
cfg.width = 1280;
cfg.height = 720;
cfg.backgroundFPS = 12;
cfg.foregroundFPS = 60;
final Runnable rebootable = new Runnable() {
#Override public void run() {
if (Gdx.app != null) {
Gdx.app.exit();
}
TestLauncher.restart();
}
};
new LwjglApplication(new RebootTest(rebootable), cfg);
}
public static void restart() {
final StringBuilder cmd = new StringBuilder();
cmd.append(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java ");
for (final String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
cmd.append(jvmArg + " ");
}
cmd.append("-cp ").append(ManagementFactory.getRuntimeMXBean().getClassPath()).append(" ");
cmd.append(TestLauncher.class.getName()).append(" ");
try {
Runtime.getRuntime().exec(cmd.toString());
} catch (final IOException e) {
e.printStackTrace();
}
}
}
Sample Game Code:
public class RebootTest implements ApplicationListener {
private final Runnable rebootHook;
private Stage stage;
private Skin skin;
public RebootTest(final Runnable rebootHook) {
this.rebootHook = rebootHook;
}
#Override public void create() {
this.stage = new Stage();
this.skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
final Table table = new Table();
table.setFillParent(true);
final TextButton button = new TextButton("Reboot", this.skin);
button.addListener(new ClickListener() {
#Override public void clicked(final InputEvent event, final float x, final float y) {
Gdx.app.postRunnable(RebootTest.this.rebootHook);
}
});
table.add(button).expand().size(120, 40);
this.stage.addActor(table);
Gdx.input.setInputProcessor(this.stage);
}
#Override public void resize(final int width, final int height) {}
#Override public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.stage.act();
this.stage.draw();
}
#Override public void pause() {}
#Override public void resume() {}
#Override public void dispose() {
if (this.stage != null) {
this.stage.dispose();
}
if (this.skin != null) {
this.skin.dispose();
}
}
}
I'm building a simple UI for ffmpeg launching ffmpeg.exe with parameters using exec(). it works on Os X but on Windows 7-8 after few seconds the ffmpeg process suspends itself and resumes only when I kill the father process. (also ddlhost.exe is created)
Ffmpeg.exe converts successfully the same video from cmd.
Searching on the internet I've found this answer but I have the same problem running a simple test program which is not using the Input and Error streams.
Here is the test program code which has the same problem of the main one:
public class Main {
static String param_ffmpeg_1 = "./data/ffmpeg.exe";
static String param_ffmpeg_2 = "-i";
static String in = "./data/source.mov";
static String out = "./data/out.flv";
static Process p;
public static void main(String[] args) {
/*File f = new File(out);
if (f.exists()){
f.delete();
}*/
Runtime rt = Runtime.getRuntime() ;
//String cmd1 = param_ffmpeg_1 + param_ffmpeg_2 + in_path + param_ffmpeg_3 + out_path ;
System.out.println(in);
System.out.println(out);
String[] cmd1 = new String[] { param_ffmpeg_1, param_ffmpeg_2, in, "-ar", "44100", "-vb", "2500k", "-s", "882x496", "-f", "flv", out};
try {
p = rt.exec(cmd1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int r = 123456;
try {
r = p.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(r);
}
}
Does ffmpg write anything to the stdout or stderr? If yes you have to consume that. (In seperate threads as you need to consume the stderr and the stdout in parallel) see Process.getInputStream() and Process.getErrorStream() for the details. When the buffer is buffer is full your called programm is stopped and hangs.
The fact that it works in OS/X but not Windows might be caused by different buffer sizes.
You should call getInputStream() and getErrorStream() on the Process returned by Runtime.exec and drain that all the time the process is running. If you do not then it will eventually fill up and block and stop the process from running.
See Java Process with Input/Output Stream for examples.
From the accepted answer
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream itsOutput = process.getInputStream();
// Wrap the stream in a Reader ...
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Am running .exe file from java code using ProcessBulider, the code I have written is given below. The .exe file takes Input.txt(placed in same directory) as input and provide 3 output file in same directory.
public void ExeternalFileProcessing() throws IOException, InterruptedException {
String executableFileName = "I:/Rod/test.exe;
ProcessBuilder processBuilderObject=new ProcessBuilder(executableFileName,"Input.txt");
File absoluteDirectory = new File("I:/Rod");
processBuilderObject.directory(absoluteDirectory);
Process process = processBuilderObject.start();
process.waitFor();
}
this process is working fine by call ExeternalFileProcessing(). Now am doing validation process, If there is any crash/.exe file doesn't run, I should get the error message how can I get error message?
Note: It would be better that error message be simple like run successful/doesn't run successful or simply true/false, so that I can put this in If condition to continue the remaining process.
You can add exception handlers to get the error message.
public void externalFileProcessing() {
String executableFileName = "I:/Rod/test.exe";
ProcessBuilder processBuilderObject = new ProcessBuilder(
executableFileName, "Input.txt");
File absoluteDirectory = new File("I:/Rod");
processBuilderObject.directory(absoluteDirectory);
try {
Process process = processBuilderObject.start();
process.waitFor();
// this code will be executed if the process works
System.out.println("works");
} catch (IOException e) {
// this code will be executed if a IOException happens "e.getMessage()" will have an error
e.printStackTrace();
} catch (InterruptedException e) {
// this code will be executed if the thread is interrupted
e.printStackTrace();
}
}
But it would be better to handle it in the calling function by put a try catch handler in the calling function and handling it there.
Is it a third party .exe or do you have access to its sources? If so, you could work with basic System outputs (for example couts to the console).
Those outputs can be redirected to your java app using something like this:
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null) {
if(line.equals("something")) {
// do something
}
}
br.close();
This is how i do things like that and it works very well in general. But i must admit, that i can not say/garuantee, that this is THE way to do it. A more advanced approach might be the use of StreamGobbler (see Listing 4.5) to handle the outputs of the .exe.
Let me know if it helped you or not.