Why is my process hanging at input.readLine()? - java

I have a utility where Jmeter sends a request and the utility sends back response to Jmeter. When load increases, the Utility shuts down with an "EXCEPTION_ACCESS_VIOLATION".
Since it is an error, I am not able to handle it in a catch block. I made a second utility to restart the first utility when the error occurs. Below is the code of the second, restart, utility. In this second utility's code, at the second while, my program sometimes hangs. How do I detect this and restart the process?
public static void main(String[] args)
{
String line = null;
String currPID = null;
try
{
while(true)
{
Process process = Runtime.getRuntime().exec("java -XX:+HeapDumpOnOutOfMemoryError -Xms250M -Xmx500M -XX:ErrorFile=NUL ws ");
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = input.readLine()) != null) //Program stucks at this Line
{
if(line.trim().length() != 0)
{
if(line.startsWith("PID"))
{
currPID = line.substring(line.indexOf("#")+1);
}
}
}
System.out.println("Ended");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
I analysed process through jvisualvm where i found two java process is in running mode when i start second(restart) utility. I can see first utility is restarting regularly because its PID is changing frequently in jvisualvm and same happening in task manager. Everything is going on very well manner.
After sometime i found only one process is in Jvisualvm ie second(restart) utility.
It means first utility JVM is crashed just guessing not sure. Something unusual is happening here. Because if JVM is crashed so It should be restarted.
So i opened task manager and found first utility PID exists there but it is not changing as happening in starting. If i kill the process(first utility) explicitly from task manager.
Seconds utility again restarts first utility same thing happens again, After some time first utility disappeared from jvisualvm, exists in taskmanager and delete process from taskmanager. What needs to do?

Try using .ready() function.
try {
if (stdError.ready())
{
while((line= stdError.readLine()) != null){
logger.error(line);
}
}
}
Do the same for the stdout.
It worked like a charm for me.

Your problem with hanging appears to be at the call to readLine.
readLine is for reading lines. The method will not return until the call is sure the end of line has been reached. It expects either a newline character or the complete cease of communications.
Is your first utility not sending a new line char?
Does your first utility fail to close the stream?
Your while call will hang indefinitely if the answer to both questions is yes.
You might be better off consuming with a custom implementation of the Scanner class.

Try to use getErrorStream() it'll catches the error message, if you use getInputStream() it'll reads only the success message or feedback messages.
for ex: if you execute the following command & read the process message using getInputStream(),
Process process = Runtime.getRuntime().exec("net use u: \\sharedIP\sharedFolder");
BufferedReader input = new BufferedReader(new inputStreamReader(process.getInputStream()));
you can only get feedback messages like "network drive connected successfully" but not the error messages.
if you use getErrorStream() to read the process message it'll read the error messages like "the network drive was not found". when the process executed it'll give a message to either getInputStream() or getErrorStream(). so use both method to read the message from the process, if i'm correct this'll work. I'm just trying to give you an idea but i'm not sure.

Related

Java ProcessExplorer is there a way to allow a remote machine to handle the process run?

working on a problem where ProcessBuilder is being used to start a batch file on a remote machine. However I wan't to have the ability to either wait for the processes completion or not. When waiting everything works perfectly, however when not waiting the process never actually finishes on the remote machine. I believe this is because I am returning immediately after starting the process and this is causing a hang (process which should take 1 second to 1 minutes is running for 15 minutes before finally closing). Is there a way I can get the process to finish and not have to wait for it to complete? Any help would be appreciated.
Path batchFile = pathService.getFilePath(login.getNode(), "run.bat");
// When file does not exists there is no point in executing it
if (!Files.exists(batchFile)) {
return;
}
try {
// Run batch file
Process process = new ProcessBuilder(ImmutableList.of(
"cmd",
"/c",
batchFile.toString()))
.directory(pathService.getRootPath(login.getNode()).toFile())
.redirectErrorStream(true)
.start();
if (!waitForCompletion) {
return;
}
String standardOutput = collectString(process.getInputStream());
String standardError = collectString(process.getErrorStream());
if (!process.waitFor(120, TimeUnit.SECONDS)) {
LOGGER.warn("Process '{}' is hanging with output '{}' and error '{}'", batchFile.toString(), standardOutput, standardError);
}
} catch (IOException | InterruptedException e) {
LOGGER.error(e.getMessage());
}
Note the warnings of the Process javadoc:
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 process may cause the process
to block, or even deadlock.
When you exit your method early with if (!waitForCompletion) then you skip consuming stdout. If your sub-process is writing a lot of output to stdout then it will block if stdout buffer is filled => process freezes.
If that is the case, you can avoid the issue by one of:
Add .inheritIO() when ProcessBuilder to ensure output is passed onto default for current Java process
Send STDOUT/ERR to a file instead, adding .redirectInput(new File("somefile.log"))
Add a background task to consume stdout, something like this but with suitable try/catch in the Runnable for you to deal with IOException / logging etc:
if (!waitForCompletion) {
// Ensure STDOUT is consumed
new Thread(() -> collectString(process.getInputStream())).start();
}

Invoking Seagull Diameter Client using Java

i need to send some messages from my java web application to some servers using Diameter protocol, in particular CCR-CCA scenario. I had a look at jdiameter opensource project, but my usecase does not require such complexity, since that i just need to send a single request and log the response (actually i don't even need the CER-CEA part).
So i thought i could just have used Seagull running under my webapp. I downloaded Seagull (for Windows), and what i'm trying to do is basically to run the .bat file coming from Seagull for the diameter environment from my java environment.
That's what i've done till now..
1) A simple test to invoke the client.. Here wrapper simply sets working dir and starts the process
public static void main(String[] args) {
List<String> cmd=new ArrayList<>();
cmd.add("cmd.exe");
cmd.add("/c");
cmd.add("my_start_client.bat");
JavaProcessBuilderWrapper wrapper = new JavaProcessBuilderWrapper();
Process p = wrapper.createProcess(RedirectErrorsTo.STDERR,
new HashMap<>(), new File("my_working_dir"), cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
output.append(line);
}
System.out.println(line);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2) I modified the client's and server's .bat files coming from Seagull to use CCR-CCA protocol.
Running Java main with this configuration caused a
Fatal: Keyboard saved configuration failure error
on my logs.
3) So, as mentioned here i further modified my client's .bat file to run in background mode, adding -bg at the end. Now my client's bat look like this
#ECHO OFF
rem
"Diameter Start Script Sample"
"Local env"
SET RUN_DIR=C:\Program Files\Seagull
set PATH=%PATH%;%RUN_DIR%
set LD_LIBRARY_PATH=%RUN_DIR%
set RUN_DIR=%RUN_DIR%\diameter-env\run
cd %RUN_DIR%
cls
mode 81,25
echo "Seagull Diameter Client Sample Start"
seagull -conf ..\config\conf.client.xml -dico ..\config\base_ro_3gpp.xml -scen ..\scenario\ccr-cca.ro.client.xml -log ..\logs\ccr-cca.client.log -llevel ETM -bg
pause
Since i was facing some troubles, to keep things simple, i just tried to make it work at least via cmd (not using my java method), but i think background mode is messing around, because now when i start my server and then my client in bg mode, sometimes i get a
Fatal: Forking error
but the most of the times, the client send a single message and then on my console i see that my software is causing connection abort (error code -1), and from the log i see that the channel just get closed, and my client does not even receive an answer. (NB for now i left the configuration files untouched)
Has any of you faced this behaviour? Is something else closing the connection (firewall perhaps)? Do i have to provide other configurations to make this work?
Once i can get this working, can i use my java web app (with a method similar to the one i already mentioned) to make diameter calls?
Thanks in advance, any help is really welcomed.

Console program doesn't react on sending \n to stdin

I'm writing GUI using JAVA for a console program. It starts and works well, but when i send "\n" or "\r\n" to it's stdin it doesn't react as it reacts if i simply start this program in Terminal and press "Enter".
This code is used to start process:
String cmd="example.exe";
process = new ProcessBuilder(cmd).start();
And this code is used to send "\n"
OutputStream outputStream = process.getOutputStream();
outputStream.write("\n".getBytes());
outputStream.flush();
In other thread i'm trying to read from this process
while ((line = is.readLine()) != null && !Thread.currentThread().isInterrupted()) {
...
}
How can i properly send "\n" to receive information from the process?
Update:
I need to send a new line symbol. Or "Press Enter".
I read out and error, both are empty.
Application always reports it's status as reaction to pressing enter. So no reaction is a bug.
Presumably you are expecting the newline written to outputStream to trigger something that you can read using is.
Here are a couple of possible causes:
You could be reading from the wrong stream. The external program might be writing to "standard error" and you are reading "standard output" or vice-versa.
The external application might be failing to flush. For example, it (or the I/O library it uses) might only flush output after each newline if the output is directed to an interactive output stream (e.g. a "console"). The pipe connecting program output to your JVM might not show up as interactive.
These are only guesses ...
If I was trying to debug this, I would try to determine whether the problem is that the newline doesn't get to example.exe, that the response doesn't get written / flushed by example.exe, or that the Java side is failing to read it ... for some reason.

How does TCP chat program both send and receive data from the same thread?

I have noticed that in a few pieces of example code for a TCP chat program, written in Java, both the read string from client and send string to server both occur in main.
For example, here is a tutorial where I don't see the distinction between an input thread and in output thread... http://www.cise.ufl.edu/~amyles/tutorials/tcpchat/TCPChat.java
"BufferedReader input" and "PrintWriter output" are both used with a TCP Socket from within the same thread. As a complete novice, this confuses me because previously, if I had something that waits for input, like the "getch()" get character function from C, that thing that will hold up the thread (unless it is an event or an exception). Normally, when I imagine code in a thread being executed, I imagine it being executed line by line, with occasional jumps in execution for exceptions and events. But writing to a stream and reading from a stream is neither an exception nor an event - I don't know what the main thread would do if it received an input string and was supposed to send out an output string both at the same moment. Is the stream itself actually handled by some other thread or some other program, like the terminal or the OS?
I had felt so weird about this that I split the chat program into two separate threads to make me feel more comfortable - one thread for receiving strings from the TCP socket and another thread for sending strings out through the same socket. Can someone provide an explanation as to why my act of splitting input and output into two separate threads is totally unnecessary? And before someone marks this down due to lack of research and understanding, I did my best to read online Java tutorials on Sockets and I have had experience writing to and reading from streams (terminal and plain text file).
case CONNECTED:
try {
// Send data
if (toSend.length() != 0) {
out.print(toSend); out.flush();
toSend.setLength(0);
changeStatusTS(NULL, true);
}
// Receive data
if (in.ready()) {
s = in.readLine();
if ((s != null) && (s.length() != 0)) {
// Check if it is the end of a trasmission
if (s.equals(END_CHAT_SESSION)) {
changeStatusTS(DISCONNECTING, true);
}
// Otherwise, receive what text
else {
appendToChatBox("INCOMING: " + s + "\n");
changeStatusTS(NULL, true);
}
}
}
}
catch (IOException e) {
cleanUp();
changeStatusTS(DISCONNECTED, false);
}
break;
I took this code snippet from the "main procedure" of the link you provided.
The method that would halt the thread from continuing like you were talking about is in.readLine(); The thread would wait until there was something to read from the input stream before continuing. I would like to point out the if statement " if(in.ready()) " By having that if statement there, the code checks first if the input stream has something to read. Otherwise, it skips over it and continues.

ProcessBulder loads the process but doesn't start it

I use ProcessBuilder to start a new process (child) form a java application (host). Something like this:
ProcessBuilder processBuilder = createProcess(commandLine);
processBuilder.directory(new File(baseDir));
processBuilder.redirectErrorStream(true);
Process process = null;
try {
process = processBuilder.start();
} catch (Exception e) {
e.printStackTrace();
}
I do see in the system monitor that the child process has been started but it's not functioning unless I stop the host application. More specifically the child proecess is a server and after starting it with a ProcessBuilder it's not responding to the requests if the host application still is running. Moreover, the port that server is using still is available. The server starts working immediately if I stop the host application. Is there anything that I missed or that's how ProcessBuilder suppose to work?
Many thanks in advance.
Under most circumstances, until a process's standard out buffer is emptied, it will not terminate. It might be that your process has filled this buffer and has stopped (for some reason)
Try consuming the processes standard out (via Process#getInputStream) and see if that makes a difference.
It could also be that the process is waiting for input for the user.
Take a look at I'm not getting any output and probably the machine hangs with the code for an example
#MadProgrammer is correct. I was able to fix the issue and I want to answer to my question with a code example. That could be usefull for others too.
You need to consume the standard out of the child process after starting it. Something like this:
process = processBuilder.start();
InputStream is = process.getInputStream();
INputStreamReadr isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while (!stopProcess) {
if (br.ready()) {
line = br.readLine();
System.out.println(line);
}
}

Categories