So I have this Java program that creates processes that run a certain C program on the terminal (unix), and I need to notify the Java program when something happens in the C program (before the termination). How can I do this? I know that I'm gonna need signals, but I don't have much experience on the subject.
Thanks in advance!
EDIT: This the changes I made to the java, after calling the process:
InputStream stdout = p.getInputStream();
InputStreamReader isr = new InputStreamReader(stdout);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<INPUT>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</INPUT>");
int exitVal = p.waitFor();
System.out.println("Process exitValue: " + exitVal);
I what I did in the C when I want to notify the java:
char buff[20];
size_t nbytes;
ssize_t bytes_written;
int fd;
strcpy(buf, "This is a test\n");
nbytes = strlen(buf);
bytes_written = write(1, buff, nbytes);
But after running it I only get:
INPUT
/INPUT
Process exitValue: 0
One of the ways is reading your C program's stdout
Process p = Runtime.getRuntime().exec("c.exe");
InputStream stdout = p.getInputStream();
now C program can talk to Java program
You can create a socket using c program and send it to java socket server. You can search on goole to find out sample.
Easiest way to communicate between a Java program and another program spawned by it, is using the FIFO streams that are set up when you launch a subprocess. So, for example, if you launched your subprocess using Runtime.exec() or using ProcessBuilder, you have an object of type Process. By calling its getInputStream() you can have access to the process' stdout.
In the native code, just print your signals out to stdout and they can be read by the Java process.
You can use Signals with Java, but this is not the best mechanism. I would look at using JNI, JMS, Socket, RPC or some other solution first. The problem with signals is that it doesn't allow you to transmit much information and it's the easiest to get right or debug.
For more details on signal handling and Java
http://www.oracle.com/technetwork/java/javase/signals-139944.html
http://www.ibm.com/developerworks/java/library/i-signalhandling/ (link dead)
http://ringlord.com/dl/Signals-in-Java.pdf
Related
I have this code
private static void restartTor() throws IOException, InterruptedException {
String killTor = "killall tor";
String startTor = "/opt/local/bin/tor -f /dev/torrc";
Runtime run = Runtime.getRuntime();
Process pr = run.exec(killTor);
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
pr = run.exec(startTor);
pr.waitFor();
buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
}
When I run this on computer A it executes as expected but when I run it on my second computer, B, it gets stuck at the second pr.waitFor();.
I have read a bunch of questions here on SE, such as process.waitFor() never returns and Java process.waitFor() does not return and the main issue there seems to be that you don't read the buffer but I do that (don't I?).
A and B are similar, but not identical (Macs, running 10.15, A has 32 GB RAM, B has 16 GB RAM).
I use the same version of tor and the torrc:s are identical on A and B.
I am stumped. What is the problem here?
Edit: On B, If I manually, from a regular terminal, kill the process, it returns and everything continues as expected.
Edit 2: Now it fails on computer A as well. I had run it dozens of times there, without problems before but now it fails constantly.
I don't know if this this is the ultimate cause of your problem, but you should call waitFor after reading the output (and errors) from the external process. If a process writes more to its standard output and error streams than the OS is prepared to buffer, then your code could deadlock:
The external process is blocked while trying to write output
Your Java code is blocked waiting for the external process to exit.
You need to consume both streams at same time if you are experiencing the stream deadlock issue on waitFor(). You can do this with background threads on pr.getErrorStream(), or set up STDERR handling before calling waitFor().
To do this replace use of Runtime.exec with ProcessBuilder.
ProcessBuilder pb = new ProcessBuilder(startTor);
This is easier with either sending error log to a file:
File stderr = new File("stderr.log");
pb.redirectError(stderr));
... or just redirect error to merge it with stdout:
pb.redirectErrorStream(true);
then
pr = pb.start();
pr.waitFor();
I call a external Python script as Java process and want to send data to this. I create a process and try to send a string. Later the python script should wait for a new input from Java, work with this data and wait again(while true loop).
Python Code (test.py):
input = input("")
print("Data: " + input)
Java Code:
Process p = Runtime.getRuntime().exec("py ./scripts/test.py");
BufferedWriter out = new BufferedWriter(new
OutputStreamWriter(p.getOutputStream()));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
System.out.println("Output:");
String s = null;
out.write("testdata");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
The process and output of simple prints works, but not with input and BufferedWriter.
Is it possible to send data to this python input with a Java process?
I read from other solutions:
create a Python listener and send messages to this script
import the external script to Jython and pass data
Are this better solutions to handle my problem?
use Process class in java
what is process class ?
this class is used to start a .exe or any script using java
How it can help you
Create your python script to accept command line variables and send your data from java class to python script.
for Example:
System.out.println("Creating Process");
ProcessBuilder builder = new ProcessBuilder("my.py");
Process pro = builder.start();
// wait 10 seconds
System.out.println("Waiting");
Thread.sleep(10000);
// kill the process
pro.destroy();
System.out.println("Process destroyed");
Later the python script should wait for a new input from Java
If this has to happen while the python process is still a subprocess of the Java process, then you will have to use redirection of I/O using ProcessBuilder.redirect*( Redirect.INHERIT ) or ProcessBuilder.inheritIO(). Like this:
Process p = new ProcessBuilder().command( "python.exe", "./scripts/test.py" )
.inheritIO().start();
If the python process is going to be separate (which is not the case here, I think) then you will have to use some mechanism to communicate between them like client/server or shared file, etc.
How to get the output of the command prompt which means i have opend a command prompt like this.
Process process = Runtime.getRuntime().exec("cmd /c start cmd.exe /K \"C:\\Editor\\editorTemp.exe\"");
i can not get the cmd output like this
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
So how can i get the command prompt output ?
This is not Java question. Basically what you doing is running Java (Java Main Process A) and from it starting another process (Windows CMD B). This is fine and you can get input/output streams of this process (B) in Java(A).
However this process (B) starts another process (again Windows CMD C) with its own standard input/output. This process has nothing common with processes A&B and uses Windows' standard Input/Output streams. So, there are no connections between A and C.
I'm not sure but I think there are some ways to run Windows CMD with different or not standard IO. Maybe something like this will work:
cmd <tty >tty
but there is no tty in Windows. Pragmatically you can do this as described here - Creating a Child Process with Redirected Input and Output but that would not work for regular CMD.
Nevertheless it became even more problematic when you start your own process from the editorTemp.exe (process D). D has even more disconnection with process A. And all for what? What don't you simply start process D directly from A and have full control on the IO streams and process itself?
Here is good example how to do so.
Your java thread is working independently of CMD call. The java code is beating the STDOUT pipe before anything is written.
If you call Process.waitFor(), it will wait until the CMD call is done. The STDOUT should be in the buffer, and then you can read it.
When you do a readLine(), your java thread is blocked until you have an actual full line or the input stream is closed.
If the program prints a partial line (without CR or LF at the end), and then waits for input, the readLine will be stuck.
So you will need to read character by character, until you think the proces has no more things to say.
See e.g. Is it possible to read from a InputStream with a timeout?
import java.util.Scanner;
Inside the main write this.
Scanner output = new Scanner(System.in);
System.out.println(“Enter your name”);
String name = output.next();
If you want user to enter an int then you need to do this.
int number = output.nextInt();
I'm trying to start some .jar inside an .jar using this code: (I'm trying with craftbukkit server right know)
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java -jar craft.jar");
BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter in = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
this.running = true;
while(this.running){
String line;
if((line = out.readLine()) != null){
System.out.println(line);
}
}
The problem is, it work for a moment, but after a while it stops outputting or just print '>' as show in the image below. How can I fix this? **Plus, Which is the correct way to send commands to the bukkit server?
Thanks!
When using a Process in Java, it is crucial to read stdout and stderr in two independend threads (your while loop). Otherwise the child process can lock up waiting for the filled buffer to be drained.
With Java 7 you can actually redirect stderr to stdout, and possibly redirect the resulting stream to the parents stdout. With older versions you need to attach the seperate threads.
Besides: you should not use the "single string" variant of exec, but specify the args as arrays. This is safer (less vulnerable to parsing problems).
(But I am not sure if this is your actual problem. Maybe you should dump the error stream and see if it helps)
I do it like that:
#Override
public void run(){
// ...
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); //of course proc is an instance of Process, and it's set up
while(true){
String line = stdInput.readLine();
if(line == null) break; //this is essential, when process terminates, line gets null
System.out.println(">"+line);
}
// ...
}
Give it a try.
(Technically it's similiar how you did, but it works for me so i share it)
I have an execute(String cmd) in a jsp script that calls the exec method from the Runtime class.
It works when I call a local command, like a php script stored on the server. for example: /usr/bin/php /path/to/php/script arg1 arg2
So I guess my execute command is ok, since it is working with that.
Now when I try to call lynx, the text-based web browser, it does not work.
If I call it in a terminal, it works fine:
/usr/bin/lynx -dump -accept_all_cookies 'http://www.someurl.net/?arg1=1&arg2=2'
But when I call this from my execute command, nothing happens...
Any idea why?
This is my execute method:
public String execute(String cmd){
Runtime r = Runtime.getRuntime();
Process p = null;
String res = "";
try {
p = r.exec(cmd);
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line = null;
//out.println(res);
while ((line = br.readLine()) != null) {
res += line;
}
p.waitFor();
} catch (Exception e) {
res += e;
}
System.out.println(p.exitValue());
return res;
}
You need to read from the Process' output stream.
Since you're not, the underlying lynx process is likely blocking while writing output, waiting for someone to empty the output stream's buffer. Even if you're going to ignore the output, you need to read it anyway for the process to execute as you'd expect.
As the javadocs of Process say, "Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock."
See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html for some examples of how to handle this.
Edit: in case you are wondering, chances are that when you invoked the PHP script it didn't produce a great deal of output, and so was able to terminate before filling the output buffer and blocking. The lynx command is presumably producing more output and hence hitting this issue.
I solved it.... by calling lynx into a php script, php script that I called from the Jsp script...
It's a shitty solution but at least it works... I still do not really understand why the exec command from Java works that way...
Thanks for your help anyway Andrzej (Czech I guess from the name..? ^_^), somehow you put me on the way!