I am running rsync through my java application.(Solaris Evn)
The Java application will sync the files with remote machine. During our connection failure testing we noticed an issue running rsync through java program. The java application which is running at source side is not receiving any error message if there are any connection issues during the sync process.
Brief details about the test scenario:
We run the Java Program
The java program starts the rsync command and sync the large number of files from source to remote destination
During the sync process we run the ps -ef | grep rsync to check whether the processes are running or not at both(source and dest) side. Both side rsync processes are running.
We identify the rsync process id at target machine and kill the process with kill -9 <pid>
The java code didn't receive any error message and didn't exit. It just hung.
And also noticed that the rsync process is still running at source side and rsync process is also not printing any log message in the log file.
Note : If we run the rsync command directly (not through java program) , then everything is working fine. When we stop the rsync process at target the source process will be stopped.
When RSYNC terminated at target, the Java program and RSYNC is not detecting that the target has issues. No log files written , Java program will hang and becomes unresponsive.
Through perl its working fine. Not sure what the problem with java...!!!
I don’t have any clues to debug this issue.
Please share your thoughts and pointer to debug.
In your Java side I recommend creating two additional threads to consume the p.getInputStream() and p.getErrorStream() streams of your Process p. I think that helps rsync feel more loved and cared for.
Something like this (I'm ignoring IOExceptions for simplicity --- you'll have to deal with them!):
final Process p = Runtime.exec("rsync"); // however you do this...
Runnable consumeIn = new Runnable() {
public void run() {
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null ) {
// Throw away the data? Or do something with it if you like!
}
}
};
Runnable consumeErr = new Runnable() {
public void run() {
InputStream in = p.getErrorStream();
// etc... (very similar to consumeIn)
}
};
new Thread(consumeIn).start();
new Thread(consumeErr).start();
Related
Info about the project: I am creating a C++ console application that manages a Minecraft server by listening to port activity. When server port is pinged, it starts the server and then periodically checks if there are established connections on that port. If none, the server is shut down and app goes into listening mode once again.
The problem arises when the server is stopped. Somehow my main console app is getting killed by the child server process and I can't seem to find out how and why or any solutions to this.
My console app creates a new cmd.exe child process that runs a "java -jar server.jar" command when starting the server. When stopping the server a simple "stop" message is written to the standard input of the child process. This all works fine and the java server stops.
However as soon as the child process exits, the console app unexpectedly crashes and the Windows "Program has stopped working." dialog appears. The curious thing is that I have tested the application on my programming laptop that runs Windows 10 and it runs without any issues there both in release and debug mode. My server machine is running Windows 7 however, so it seems to somehow be a Windows 7 problem.
Now there's no code I can really show you since it's the java and cmd.exe child process performing the exit and I of course didn't code the server.jar file. But I will attach an image link of the console when it crashes just for fun.
The child process does not have a separate window, it inherits handles from the parent console app and writes to the parent's STDOUT so messages from the child show in the main app's console.
I have tried starting the child process with CREATE_NEW_PROCESS_GROUP flag, still crashes.
I have tried ignoring SIGINT and SIGTERM signals, still crashes.
I have also verified that the application doesn't start execution of the commands following the server shutdown call (writing stop message to stdin of server process) so they can't be the problem.
If anyone has any tips or ideas about what could be the issue I'm all ears. Thanks!
Console application crashes, Windows "Program has stopped working." dialog is not shown on picture.
EDIT:
Okay, so I created a minimal reproducible example. Here is all the needed code (for C++ main function):
//security attributes for pipes
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
//handles for child standard input/output
HANDLE child_stdin_rd = NULL;
HANDLE child_stdin_wr = NULL;
if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &saAttr, 0))
return -1;
if (!SetHandleInformation(child_stdin_wr, HANDLE_FLAG_INHERIT, 0))
return -1;
STARTUPINFOW startupInfo;
ZeroMemory(&startupInfo, sizeof(STARTUPINFOW));
startupInfo.cb = sizeof(STARTUPINFOW);
startupInfo.hStdInput = child_stdin_rd;
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
//cmd.exe path
wstring exepath = L"c:\\windows\\system32\\cmd.exe";
//cmd command to start server
wstring command = L"cmd.exe /c java -Xms1G -Xmx4G -jar server.jar nogui";
LPWSTR com = new wchar_t[command.size() + 1];
copy(command.begin(), command.end(), com);
com[command.size()] = 0;
if (!CreateProcessW(exepath.c_str(), com, 0, 0, TRUE, CREATE_NEW_PROCESS_GROUP, 0, 0, &startupInfo, &processInfo))
return -1;
//sleep for 1 min, letting server start up
this_thread::sleep_for(chrono::minutes(1));
//command to stop server
string stopCmd = "stop\n\0";
DWORD stopCmdByteSize = stopCmd.size() * sizeof(char);
if (!WriteFile(child_stdin_wr, stopCmd.c_str(), stopCmdByteSize, 0, 0))
return -1;
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
CloseHandle(child_stdin_wr);
To reproduce this, your machine would need to be running Windows 7 and in the same folder as the application must be a Minecraft server.jar file (version 1.15.2 at time of writing this) which you can get from their website. Also, the server might need some setting up first, running it for the first time by double-clicking .jar file creates all needed server files, you must open "eula.txt" and accept the EULA by changing eula=false to eula=true. Then the server should be good to go.
Like stated before, I didn't code the server.jar file and thus do not know the complete behavior of the java server program.
Bug found! Problem solved!
Ahh, after some vigorous thinking and reading the docs again to verify the code is correct I found the culprit.
In the call to the WriteFile() function I forgot to give it a pointer to a DWORD so that it can update the number of bytes the function has written.
So the following code:
if (!WriteFile(child_stdin_wr, stopCmd.c_str(), stopCmdByteSize, 0, 0))
return -1;
Needed to be changed to:
DWORD bytesWritten = 0;
if (!WriteFile(child_stdin_wr, stopCmd.c_str(), stopCmdByteSize, &bytesWritten, 0))
return -1;
So I guess it was a kind of undefined behavior that Windows 10 could handle but Windows 7 couldn't, resulting in the program crashing.. Kind of feel embarrassed for writing this lengthy post because of a small error in a function call, but there you have it folks! Thanks to those who gave tips! :)
You may have better luck using RCON, which is a protocol built into the Java edition server used to remotely manage a server with a simple TCP packet format, rather than trying to write commands to the standard input of the server directly.
See wiki.vg's page on RCON for an explanation on the packet format.
I searched everywhere but can't find a solution that works.
I have a Linux Debian machine in my network, which is running as a Mqtt Broker. I want to write a java programm to send sub and pub commands to the broker from another computer (Windows). Is there a way to send Linux commands from a Windows Computer?
If yes, is it possible to do it through java code and recieve the proper outputs?
I tried the following:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class AA
{
public static void main(String[] args) throws Exception
{
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c",
"ssh 10.20.0.30 -l username"); // Ip of the Mqtt Broker
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line;
while (true)
{
line = r.readLine();
if (line == null)
{
break;
}
System.out.println(line);
}
}
}
The output is:
Pseudo-terminal will not be allocated because stdin is not a terminal.
I feel like this might work, if the right commands would be added.
I have heard of libraries like "Eclipse Paho", but I want to know if my solution can work.
Thanks in advance!
Your solution can work if you fallow this approach Run a command over SSH with JSch
but you mention MQTT. therefore you dont need to use ssh. you can connect to mqtt and make run commands with it. here is mqtt connection example https://www.hivemq.com/blog/how-to-get-started-with-mqtt
Try using ssh -tt in your code which might work for you.
From ssh manpage:
-t Force pseudo-tty allocation. This can be used to execute arbitrary
screen-based programs on a remote machine, which can be very useful,
e.g. when implementing menu services. Multiple -t options force tty
allocation, even if ssh has no local tty.
`I have written a below code for running exe that presently is ran through windows service. I want to call it by java program. But i am getting below error in image. I dont know how to go through installutil or debug this error. Please help me on this.
`
import java.io.*;
public class exec {
public static void main(String[] args)throws Exception {
try {
String cmd = "D://OGLWindowsService//OGL_21052014//OGL_25_Feb_2015//OGLService.exe";
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
}
catch(Exception ex) {
System.out.println(ex.getMessage());
}
}
}
You actually have the answer for your question in your first screen. windows tells you that this program is designed to be the Service and could not run from the command line. It also suggests that you use insyalutil to set your program as a service and then Windows will run it when it will need it.
Ususally service runs for some events. Most common - user connects to particular port associated with this service (for example port 80) and when such request occurs then Windows starts service progarm (IIS to answer http call) and delegate this request to this new program. Or delegeates it immediately if program is already running.
So, as you can see, Windows is in charge of the service programs. You cannot start them from command line of from another process (that's your example). You can start/stop/restart process manually in the service control window but that's still not command line or your process.
I have my middle layer jar file running on the linux server. I want that jar file running in background non-stop.
nohup java -jar RushMiddleLayer.jar &
But when i re-run this command, another new instance of the jar created and running.
I have searched through google. They suggested some options.
"Bind a ServerSocket". But which is not working for me. Process killed after press enter or Ctrl+C.
I want to have two benefits from the jar. One is always running with fail. Another if restart the jar using the same command (nohup java -jar RushMiddleLayer.jar &).
It should replace the existing jar, not create the new instance.
Just to make sure I understand what you want, you want a jar file that runs in the background and it is only able to be launched once and once only?
If this is what you want, there is two ways to achieve this:
Use a port as a semaphore (as you suggested)
Use a file as a semaphore.
For option 1,
The code should be as simple as something like:
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.out.println("Could not listen on port: " + port);
// ...
}
An IOException will be thrown, if you cannot open server socket on this port. However, this could also occur if some other application is using this port. So be careful what port number you choose.
For option 2,
You simply use a FileWriter and create a dummy file and keep this file open until the jar/program is finished (or closed). When a second instance of the jar attempts to open, an exception will be thrown and it won't be able to start due to the fact that it will try to open the file for writing which produces an IOException because only one process can have a write handle to a file at the same time.
I have my application in Java which invokes a browser [IE or Firefox etc ] ..
Requirement is when my Java Application exits i have to kill all the web pages [Child processes ] i have opened from my Application in IE/Firefox etc..
I use the following code .
Note : cmd contains "System Browser exe path and URL"
static ArrayList<Process> pro = new ArrayList<Process>();
String cmd=" ";
Process p = Runtime.getRuntime().exec(cmd);
pro.add(p);
I maintain a static arraylist to add all the process objects .
To kill the process i invoked i use the below code
Iterator<Process> iter = pro.iterator();
while(iter.hasNext()){
Process p = iter.next();
System.out.println("Now Killing "+p.toString());
p.destroy();
}
This code[p.destroy();] is working fine for Internet Explorer , But its not working for Firefox/Chrome...
Since Firefox runs as a Main process and the process what i invoke goes as its child :(...
I have to use generic fix for Windows and Linux..
I can even go for C++ file fix which does this with some search criteria ..so that i can execute that executable from my code using
Runtime.getRuntime().exec("executable cmd");
In windows, you can run :
wmic process get description, executablepath, processid | findstr firefox
which will give you the PID of the firefox process. Then you can use tskill PID to kill
the process.
Good question.
There are several solution.
The first is the following. Run browser not directly but using script (shell for unix, bat file for windows) that will report you the process ID of the browser that it runs. Then use kill -9 PID on linux and taskkill on windows.
This solution will require you writing scripts for different platform (at list for 2).
But I have other suggestion. If the URL that you are opening in browser is yours (I mean you can add some javascript there) you can do the following. The URL that you are opening will create AJAX call to server. When you close your application you should say to server to send command to the browser to close it. At this moment javascript that is running into the browser will close its window. This is the most cross-platform solution.
BTW I think that the server that is used by mentioned AJAX component may be your own application. And the signal that you send to the AJAX component is just connection error. Really, if your application is the server and you are closing it, the AJAX call will fail. This 100% means that the browser should be closed too.
try using pkill (killing by process name) command.
Runtime.getRuntime().exec("pkill firefox");
or in c++
system("pkill firefox");
But it's not platform independent. It will run on Unix-like operating system, and not in windows.