Runtime.exec and sockets

J

Jay

I submitted this as a bug, but no response. Can anyone help?

FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Runtime.exec() to start a new java program. The new java program
should create a socket connection to another program.

The socket will connect if created and used from the static main
method. It will also work if placed in a static method called from
main. It will not work if I create an object and have the object
execute the same code (which is what I need); it fails both times if
the method is static or not static.

If I run the java program from the command line and not by using
Runtime.exec, it works beautifully.

If while it is blocking I kill the first vm, then the second vm
continues.


ACTUAL -
Blocking

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class ProgA {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java ProgB");
p.waitFor();
System.out.println("Process Returned");
}
}

///////////////////////////////////////////////////////////////////////

import java.net.*;
import java.io.*;

public class ProgB {

public void service() throws Exception {
//If I move this body of code to main or another static method,
//the program works.
Socket s = new Socket("127.0.0.1", 5000); //Blocking
OutputStream o = s.getOutputStream();
o.write("test data".getBytes() );
s.close();
}

public static void main(String[] args) throws Exception {
ProgB b = new ProgB();
b.service();
}
}


---------- END SOURCE ----------
 
T

Tony Morris

"Process p = rt.exec("java ProgB");"

Do you have a good reason for doing such a horrible thing ? I'm not even
going to begin going into detail of the limitations of this violation of
fundamental practices.

I suspect you won't receive a response, since I am quite confident that
there isn't a problem with the VM, but a problem with your code and/or
network configuration.

--
Tony Morris
(BInfTech, Cert 3 I.T., SCJP[1.4], SCJD)
Software Engineer
IBM Australia - Tivoli Security Software
(2003 VTR1000F)
 
M

Matt Humphrey

Jay said:
I submitted this as a bug, but no response. Can anyone help?

FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Runtime.exec() to start a new java program. The new java program
should create a socket connection to another program.

The socket will connect if created and used from the static main
method. It will also work if placed in a static method called from
main. It will not work if I create an object and have the object
execute the same code (which is what I need); it fails both times if
the method is static or not static.

If I run the java program from the command line and not by using
Runtime.exec, it works beautifully.

If while it is blocking I kill the first vm, then the second vm
continues.


ACTUAL -
Blocking

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class ProgA {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java ProgB");
p.waitFor();
System.out.println("Process Returned");
}
}

///////////////////////////////////////////////////////////////////////

import java.net.*;
import java.io.*;

public class ProgB {

public void service() throws Exception {
//If I move this body of code to main or another static method,
//the program works.
Socket s = new Socket("127.0.0.1", 5000); //Blocking
OutputStream o = s.getOutputStream();
o.write("test data".getBytes() );
s.close();
}

public static void main(String[] args) throws Exception {
ProgB b = new ProgB();
b.service();
}
}

I compiled and tested your code exactly as it is shown under Java 1.4.2_03
and it worked correctly. In doing so, ProgA will block and give no error
message *exactly as it should* for the circumstance described below. This
is not a bug.

In order to test your code I setup a local server on port 5000 that merely
reads and prints what it reads. When this service is running, ProgA clearly
launches ProgB and ProgB's data is output by the server. The problem you
are experiencing will occur when the local server is NOT running. In that
case ProgA still launches ProgB, but ProgB naturally throws an exception and
exits. However, you do not read this error message (on standard error) in
ProgA. This does not make the message go away. Instead, however, the output
data fills the pipe connecting to ProgA, thereby causing ProgA to block.
This is normal exec behavior. You must read all output generated by exec'd
processes.

To solve your problem, you must simultaneously (in two separate threads)
read standard output and standard error from your exec'd process. If you
print standard error you'll see the error message. The following class
creates a thread that reads and echos an input stream: When I added these
to ProgA (see code below) it no longer blocked but printed the error and
exited.

import java.lang.*;
import java.io.*;
public class StreamGobbler implements Runnable {
String name;
InputStream is;
Thread thread;

public StreamGobbler (String name, InputStream is) {
this.name = name;
this.is = is;
}

public void start () {
thread = new Thread (this);
thread.start ();
}

public void run () {
try {
InputStreamReader isr = new InputStreamReader (is);
BufferedReader br = new BufferedReader (isr);

while (true) {
String s = br.readLine ();
if (s == null) break;
System.out.println ("[" + name + "] " + s);
}

is.close ();

} catch (Exception ex) {
System.out.println ("Problem reading stream " + name + "... :" + ex);
ex.printStackTrace ();
}
}
}



public class SafeProgA {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java ProgB");
StreamGobbler s1 = new StreamGobbler ("stdin", p.getInputStream ());
StreamGobbler s2 = new StreamGobbler ("stderr", p.getErrorStream ());
s1.start ();
s2.start ();
p.waitFor();
System.out.println("Process Returned");
}
}


Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
T

Tony Morris

JAVA_HOME is an environment variable used by independant third party
applications and has nothing to do with a SDK installation.

--
Tony Morris
(BInfTech, Cert 3 I.T., SCJP[1.4], SCJD)
Software Engineer
IBM Australia - Tivoli Security Software
(2003 VTR1000F)


jerk said:
JAVA_HOME isn't set in the enviroment.

Jay said:
I submitted this as a bug, but no response. Can anyone help?

FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Runtime.exec() to start a new java program. The new java program
should create a socket connection to another program.

The socket will connect if created and used from the static main
method. It will also work if placed in a static method called from
main. It will not work if I create an object and have the object
execute the same code (which is what I need); it fails both times if
the method is static or not static.

If I run the java program from the command line and not by using
Runtime.exec, it works beautifully.

If while it is blocking I kill the first vm, then the second vm
continues.


ACTUAL -
Blocking

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class ProgA {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java ProgB");
p.waitFor();
System.out.println("Process Returned");
}
}

///////////////////////////////////////////////////////////////////////

import java.net.*;
import java.io.*;

public class ProgB {

public void service() throws Exception {
//If I move this body of code to main or another static method,
//the program works.
Socket s = new Socket("127.0.0.1", 5000); //Blocking
OutputStream o = s.getOutputStream();
o.write("test data".getBytes() );
s.close();
}

public static void main(String[] args) throws Exception {
ProgB b = new ProgB();
b.service();
}
}


---------- END SOURCE ----------
 
S

Steve Horsley

Matt said:
I compiled and tested your code exactly as it is shown under Java 1.4.2_03
and it worked correctly. In doing so, ProgA will block and give no error
message *exactly as it should* for the circumstance described below. This
is not a bug.

In order to test your code I setup a local server on port 5000 that merely
reads and prints what it reads. When this service is running, ProgA clearly
launches ProgB and ProgB's data is output by the server. The problem you
are experiencing will occur when the local server is NOT running. In that
case ProgA still launches ProgB, but ProgB naturally throws an exception and
exits. However, you do not read this error message (on standard error) in
ProgA. This does not make the message go away. Instead, however, the output
data fills the pipe connecting to ProgA, thereby causing ProgA to block.

I think you made a typo here. ProgB blocks (because no-one is emptying
its stderr pipe), and ProgA therefore waits forever for ProgB to exit.
This is normal exec behavior. You must read all output generated by exec'd
processes.

To solve your problem, you must simultaneously (in two separate threads)
read standard output and standard error from your exec'd process. If you
print standard error you'll see the error message. The following class
creates a thread that reads and echos an input stream: When I added these
to ProgA (see code below) it no longer blocked but printed the error and
exited.
<code snipped>

What an excellent well thought out reply.

Respect.

Steve
 
M

Matt Humphrey

Steve Horsley said:
I think you made a typo here. ProgB blocks (because no-one is emptying
its stderr pipe), and ProgA therefore waits forever for ProgB to exit.

Yes, thanks for catching that. ProgA is already blocking on the p.waitFor
().

Also, (just to be complete) if ProgA did not do a waitFor (), it would not
block, but it would then be impossible to tell if ProgB has done its job
because it could block because of unconsumed output at any time.
<code snipped>

What an excellent well thought out reply.

Thanks very much,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,163
Latest member
Sasha15427
Top