I'm trying to execute ping command in my Android application and be able to cancel it / send break signal. Basically I want to get ping statistics after like when you send ctrl+c to ping in any normal linux.
I have read Send Ctrl-C to process open by Java but it aims for Windows platform and tbh seems a little bit like an overkill. My code for executing the command (I'm using rxjava):
public rx.Observable<String> getPingOutput(String address)
{
return rx.Observable.create(new rx.Observable.OnSubscribe<String>()
{
#Override
public void call(Subscriber<? super String> subscriber)
{
try
{
process = Runtime.getRuntime().exec("ping -c 4 " + address);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
while ((s = stdInput.readLine()) != null)
{
subscriber.onNext(s);
}
subscriber.onCompleted();
process.destroy();
stdInput.close();
}
catch (IOException e)
{
subscriber.onError(e);
if(process != null)
{
process.destroy();
}
}
}
});
}
And starting / canceling:
RxView.clicks(pingButton)
.subscribe(new Action1<Void>()
{
#Override
public void call(Void aVoid)
{
if (isPingInProgress())
{
process.destroy();
subscription.unsubscribe();
isPing = false;
pingButton.setText("Ping");
}
else
{
if(adapter!= null)
{
adapter.clear();
adapter.notifyDataSetChanged();
}
String address = addressInput.getText().toString();
subscription = getPingOutput(address)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(myObserver);
isPing = true;
pingButton.setText("Stop");
}
}
});
So far I tried just killing the process but that immediately stops all output. And ideas how can I "gracefully" stop the ping command started by Java in Android?
EDIT
So I managed to get PID of my ping process, verified its correct via adb console. I tried to kill it using:
Runtime.getRuntime().exec("kill -INT " + getPid(process));, there is no ErrorStream output but nothing happens. Same for Process.sendSignal(getPid(process),Process.SIGNAL_QUIT);. Anyone?
Problem solved, turns out it didn't react to signals because I ran ping on separate thread.
Related
I am using "selenium-java.jar" file to open chrome headless drivers.
Now we are using threads to open headless chrome. Now what happens if there is any error then sometime threads quits without closing browser.
So i want to implement a solution that if any headless chrome is ideal for last 20 minutes then close/quit it.
I searched on google and i found may solution which is around selenium server standalone like this https://github.com/seleniumhq/selenium/issues/1106
My problem is i cannot switch to standalone server now so i have to figure out solution with current library.
So is there any way to close all headless chrome browsers which are idle for last 20 minutes?
Please guide.
I use selenium-java.jar with TestNg and whilst I don't run headless browsers I do clean up after a test run in the TestNg aftermethod, which is not quite the same as your 20 min wait, but might be of help.
When running tests on a windows OS I check for to see if the process is running by name and terminate it:
public final class OsUtils
{
private static final String TASKLIST = "tasklist";
private static final String KILL = "taskkill /F /IM ";
public static final String IE_EXE = "iexplore.exe";
public static final String CHROME_EXE = "chrome.exe";
public static final String EDGE_EXE = "MicrosoftEdge.exe";
public static final String FIREFOX_EXE = "firefox.exe";
public static boolean isProcessRunning(String processName)
{
Process process;
try
{
process = Runtime.getRuntime().exec(TASKLIST);
}
catch (IOException ex)
{
Logger.error("Error on get runtime" + ex.getMessage());
return false;
}
String line;
try ( BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); )
{
while ((line = reader.readLine()) != null) {
if (line.contains(processName)) {
Logger.log("Process found");
return true;
}
}
}
catch (IOException ex)
{
Logger.error("Error on check for process " + processName + ": " + ex.getMessage());
}
return false;
}
public static void killProcessIfRunning(String processName)
{
Logger.log("Trying to kill process: " + processName);
try
{
if (isProcessRunning(processName))
{
Runtime.getRuntime().exec(KILL + processName);
}
}
catch (IOException ex)
{
Logger.error("Error on kill process " + processName+ ": " + ex.getMessage());
}
}
...
}
When running Safari on macmini I have a similar kill command (which works for both Safari proper and also the technology preview):
public static void killSafariProcess()
{
Logger.log("Trying to kill Safari processes if running.");
try
{
Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ps ux | grep -i app/Contents/MacOs/Safari | grep -v grep | awk '{print $2}' | xargs kill -9"});
}
catch (IOException ex)
{
Logger.error("Error on kill Safari processes: " + ex.getMessage());
}
}
The custom Logger class just uses System.out.println(message)
You can probably do some analysis on the start time of the different processes that match your driver criteria. I don't think it's going to tell you how long it's been idle, but you can probably assume that if it's been running for 20 mins (assuming your test should successfully complete within minutes) that it's probably orphaned.
I found this answer that shows how you can use Java to get a list of processes and see their start time. From there you should be able to find all of the drivers that are old and kill them.
An alternative might be to use Powershell to get the processes, start time, and deal with it in that way. It just depends on what you are looking for. Here's an answer to get you started down this path.
You could subclass ChromeDriver and implement your own proxy class with a timer to quit after 20 minutes idle time:
public class TimedChromeDriver extends ChromeDriver {
Timer timeOut;
private void initTimer() {
timeOut = new Timer();
}
private void startTimer() {
timeOut.cancel();
timeOut.schedule(
new TimerTask() {
#Override
public void run() {
quit();
}
},
20 * 60 * 1000);
}
public TimedChromeDriver() {
initTimer();
}
#Override
public void get(String url) {
super.get(url);
startTimer();
}
// override every method of WebDriver and ChromeDriver in the same way
}
This will only work if your Java VM is not terminated before the timer is triggered. The garbage collector could also interfere. Overriding the finalize method is deprecated.
I would invest some analysis effort into your threads quitting ungracefully. This would solve your problems at the source.
I have a java project, which complied into an executable jar file v-agent-exe.jar. This jar is a log server, log rows is sent to it for processing.
I can execute it by using this command:
`java -jar v-agent-exe.jar -a watch -f config.ini`.
After executed, this jar file will create a ServerSocket at port 1235 and listen for incoming data from clients. After data received, the program will process the data and send the result back to the client. When I execute the jar from CMD windows, the processing is working perfect.
Now I am trying to wrap the Jar file as a Windows service (I am using Windows 10). I created a "Windows service project"
in Visual studio like below:
- Caller class have call() method to execute the jar file using process.
- AgentService is the service, which execute Caller->call() in another thread.
- Program is the main entry to load AgentService.
Caller.cs
public class Caller
{
static Process proc;
public Process GetProcess(){
return proc;
}
public void call() {
try
{
String dir = AppDomain.CurrentDomain.BaseDirectory;
proc = new Process
{
StartInfo = new ProcessStartInfo
{
WorkingDirectory = dir,
FileName = "java.exe",
Arguments = #"-jar v-agent-exe.jar -a watch -f config.ini",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
CreateNoWindow = true
}
};
proc.Start();
while (!proc.StandardError.EndOfStream)
{
string line = proc.StandardError.ReadLine();
}
}
catch (Exception ex) {
VAgentService.writeLog("Error when call process: " + ex.Message);
}
}
}
AgentService
public partial class AgentService : ServiceBase
{
private string jarPath;
private string iniPath;
static Process proc;
Caller caller;
public AgentService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
writeLog("On start");
try
{
caller = new Caller();
writeLog("Prepare to launch thread");
Thread t = new Thread(new ThreadStart(caller.call));
t.Start();
}
catch (Exception ex)
{
EventLog.WriteEntry("Demo error: " + ex.Message);
}
}
protected override void OnStop()
{
proc = caller.GetProcess();
if (proc != null && !proc.HasExited)
{
proc.Kill();
}
else
{
...
}
}
}
Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(String[] args)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new AgentService()
};
ServiceBase.Run(ServicesToRun);
}
}
After build the the service project, I have AgentService.exe.
I install it to my system using:
sc create VAgentLogging binpath= %CD%\AgentService.exe depend= lmhosts start= auto
After start the service in service.msc, I can telnet to port "1235" which the java process is listening (I am sure about
only the jar running in this port). According to the
log of java program, it still can received some part of data but seem like it cannot send back to client or something,
which cause the followed process cannot be done.
I think my problem is: the jar file can executed as standalone but somehow it sucks when wrapped under my service project.
I haven't posted the jar's code yet because I think the error is related to the Windows service project. If you need the java code, please tell me and I will update it here.
Any help would be appreciated.
I have a JAX-WS webservice that receives a string as parameter, calls a Perl script, and returns the string converted to upper case. It is running on Tomcat 8 (localhost on Eclipse).
When I type from the console:
curl -X POST --data "mystring=HelloWorld" http://localhost:8080/MyServices/api/generatePath
Everything works except for the Perl call. On the debugger I see that line is executed, but apparently nothing happens (not even errors). If I run perl /home/me/workspace/match.pl from the console it works perfectly. The path of the match.pl file is correct.
In addition, process.exitValue() return 2.
#Path("/")
public class MyServices {
#POST
#Path("/generatePath")
#Produces(MediaType.APPLICATION_JSON)
public Response generatePathService(
#FormParam("mystring") String myString) {
Process process = null;
try {
process = Runtime.getRuntime().exec("perl /home/me/workspace/match.pl --lang en");
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Response.status(200).entity(myString.toUpperCase()).build();
}
}
I got similar stuff some time ago. The solution for me was to 'accept' the output of the program. Something like this:
Process p = Runtime.getRuntime().exec(cmd);
final InputStream is = p.getInputStream();
new Thread(new Runnable() {
#Override
public void run() {
try {
while (is.available() != 0) {
is.read();
}
} catch (IOException ex) {
}
}
}).start();
You should also try to get the error stream with p.getErrorStream(). An alternative could be to change your perl program in that way that there is nothing printed to standard out or error out.
Or you call a shell script and redirect the output to dev/null (someting like ´blabla>/dev/null`.
How to check if server is online or offline, and if is offline start connecting until server is on. I have tried with this:
connectBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(rConnection).start();
}
});
public Runnable rConnection = new Runnable() {
#Override
public void run() {
boolean status = connect();
while (!status)
{
System.out.println("Connection Status: " + status);
status = Connect();
}
}
};
public boolean Connect() {
boolean status = false;
try {
s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);
System.out.println("Socket: " + s.toString());
if (s.toString() != "")
{
status = true;
}
} catch (UnknownHostException e) {
e.printStackTrace();
status = false;
s=null;
} catch (IOException e) {
e.printStackTrace();
status = false;
s=null;
} catch (NullPointerException e)
{
e.printStackTrace();
status = false;
s=null;
}
return status;
}
If server is running before staring app it connects successfully but if server is off or disconnects after some time I don't get any error message and it won't start reconnecting again. How to solve this?
Basically you may split this:
s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);
into
s = new Socket();
s.connect(remoteAddr,timeout)
And then control if connect returns on timeout or on successfull connection.
Look at this thread for a solution and keywords: How can I monitor the network connection status in Android? . Also, consider retrying requests on a new connection if the underlying connection is lost (or times out).
How to check if server is online or offline, and if is offline start connecting until server is on
Try to connect to it when you need to connect to it, and handle the failures that result. At present you seem to be trying to maintain an eternal connection, which is never going to work. The best way to detect whether a resource is available is to try to use it at the time that you need to use it. Anything is subject to numerous sources of error such as timing window problems, testing the wrong thing, testing the right thing at the wrong time, and at best to overuse of scarce resources. Rethink your requirement.
Part of a Java program I'm creating needs to talk to a service on a remote machine. That remote machine is running a service (written in Delphi I believe) on a Windows platform.
I need to connect to that machine, send command strings and receive (String) responses.
If I connect using Linux CLI telnet session I get responses as expected:
[dafoot#bigfoot ~]$ telnet [host IP] [host port]
Trying [host IP]...
Connected to [host IP].
Escape character is '^]'.
Welcome to MidWare server
ping
200 OK
ProcessDownload 4
200 OK
In the above the lines 'ping' and 'ProcessDownload 4' are me typing in the terminal, other lines are responses from remote system.
I created a Main in my Java class that will do the work to call the appropriate methods to try and test this (I've left out irrelevant stuff):
public class DownloadService {
Socket _socket = null; // socket representing connecton to remote machine
PrintWriter _send = null; // write to this to send data to remote server
BufferedReader _receive = null; // response from remote server will end up here
public DownloadServiceImpl() {
this.init();
}
public void init() {
int remoteSocketNumber = 1234;
try {
_socket = new Socket("1.2.3.4", remoteSocketNumber);
} catch (IOException e) {
e.printStackTrace();
}
if(_socket !=null) {
try {
_send = new PrintWriter(_socket.getOutputStream(), true);
_receive = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public boolean reprocessDownload(int downloadId) {
String response = null;
this.sendCommandToProcessingEngine("Logon", null);
this.sendCommandToProcessingEngine("ping", null);
this.sendCommandToProcessingEngine("ProcessDownload", Integer.toString(downloadId));
try {
_socket.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private String sendCommandToProcessingEngine(String command, String param) {
String response = null;
if(!_socket.isConnected()) {
this.init();
}
System.out.println("send '"+command+"("+param+")'");
_send.write(command+" "+param);
try {
response = _receive.readLine();
System.out.println(command+"("+param+"):"+response);
return response;
} catch (IOException e2) {
e2.printStackTrace();
}
return response;
}
public static void main(String[] args) {
DownloadServiceImpl service = new DownloadServiceImpl();
service.reprocessDownload(0);
}
}
As you will see in the code, there are a couple of sys.outs to indicate when the program is attempting to send/receive data.
The output generated:
send 'Logon(null)'
Logon(null):Welcome to MidWare server
send 'ping(null)'
So Java is connecting to the server ok to get the "Welcome to Midware" message back, but when I try to send a command ('ping') I don't get a response.
So the questions:
- does the Java look about right?
- could problem be related to character encoding (Java -> windows)?
You need to flush the output stream:
_send.write(command+" "+param+"\n"); // Don't forget new line here!
_send.flush();
or, since you create a auto-flushing PrintWriter:
_send.println(command+" "+param);
The latter has the disadvantage that the line end can be \n or \r\n, depending on the system on which your Java VM runs. So I prefer the first solution.