How to run tshark in Java to get packets in real-time? - java

I have a problem with running tshark in Java. It seems that packets arrive in bulk instead of truly real-time (as it happens when run from terminal).
I tried a few different approaches:
ArrayList<String> command = new ArrayList<String>();
command.add("C:\\Program Files\\Wireshark\\tshark.exe");
ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();
BufferedReader br = null;
try {
//tried different numbers for BufferedReader's last parameter
br = new BufferedReader(new InputStreamReader(process.getInputStream()), 1);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch...
also tried using InputStream's available() method as seen in What does InputStream.available() do in Java?
I also tried NuProcess library with the following code:
NuProcessBuilder pb = new NuProcessBuilder(command);
ProcessHandler processHandler = new ProcessHandler();
pb.setProcessListener(processHandler);
NuProcess process = pb.start();
try {
process.waitFor(0, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
private class ProcessHandler extends NuAbstractProcessHandler {
private NuProcess nuProcess;
#Override
public void onStart(NuProcess nuProcess) {
this.nuProcess = nuProcess;
}
#Override
public void onStdout(ByteBuffer buffer) {
if (buffer == null)
return;
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
System.out.println(new String(bytes));
}
}
None of the methods work. Packets always arrive, as if buffered, only when about 50 were sniffed.
Do you have any idea why this may be happening and how to solve it? It's pretty frustrating. I spent a lot of time looking at similar questions at SO, but none of them helped.
Do you see any errors in my code? Is it working in your case?

As the tshark man page says:
−l Flush the standard output after the information for each packet is
printed. (This is not, strictly speaking, line‐buffered if −V was
specified; however, it is the same as line‐buffered if −V wasn’t
specified, as only one line is printed for each packet, and, as −l
is normally used when piping a live capture to a program or script,
so that output for a packet shows up as soon as the packet is seen
and dissected, it should work just as well as true line‐buffering.
We do this as a workaround for a deficiency in the Microsoft Visual
C++ C library.)
This may be useful when piping the output of TShark to another
program, as it means that the program to which the output is piped
will see the dissected data for a packet as soon as TShark sees the
packet and generates that output, rather than seeing it only when
the standard output buffer containing that data fills up.
Try running tshark with the -l command-line argument.

I ran some tests to see how much Buffering would be done by BufferedReader versus just using the input stream.
ProcessBuilder pb = new ProcessBuilder("ls", "-lR", "/");
System.out.println("pb.command() = " + pb.command());
Process p = pb.start();
byte ba[] = new byte[100];
InputStream is = p.getInputStream();
int bytecountsraw[] = new int[10000];
long timesraw[] = new long[10000];
long last_time = System.nanoTime();
for (int i = 0; i < timesraw.length; i++) {
int bytecount = is.read(ba);
long time = System.nanoTime();
timesraw[i] = time - last_time;
last_time = time;
bytecountsraw[i] = bytecount;
}
try (PrintWriter pw = new PrintWriter(new FileWriter("dataraw.csv"))) {
pw.println("bytecount,time");
for (int i = 0; i < timesraw.length; i++) {
pw.println(bytecountsraw[i] + "," + timesraw[i] * 1.0E-9);
}
} catch (Exception e) {
e.printStackTrace();
}
BufferedReader br = new BufferedReader(new InputStreamReader(is));
int bytecountsbuffered[] = new int[10000];
long timesbuffered[] = new long[10000];
last_time = System.nanoTime();
for (int i = 0; i < timesbuffered.length; i++) {
String str = br.readLine();
int bytecount = str.length();
long time = System.nanoTime();
timesbuffered[i] = time - last_time;
last_time = time;
bytecountsbuffered[i] = bytecount;
}
try (PrintWriter pw = new PrintWriter(new FileWriter("databuffered.csv"))) {
pw.println("bytecount,time");
for (int i = 0; i < timesbuffered.length; i++) {
pw.println(bytecountsbuffered[i] + "," + timesbuffered[i] * 1.0E-9);
}
} catch (Exception e) {
e.printStackTrace();
}
I tried to find a command that would just keep printing as fast as it could so that any delays would be due to the buffering and/or ProcessBuilder rather than in the command itself. Here is a plot of the result.
You can plot the csv files with excel although I used a Netbeans plugin called DebugPlot. There wasn't a great deal of difference between the raw and the buffered. Both were bursty with majority of reads taking less than a microsecond separated by peaks of 10 to 50 milliseconds. The scale of the plot is in nanoseconds so the top of 5E7 is 50 milliseconds or 0.05 seconds. If you test and get similar results perhaps it is the best process builder can do. If you get dramatically worse results with tshark than other commands, perhaps there is an option to tshark or the packets themselves are coming in bursts.

Related

Java process stuck at getRuntime().exec() [duplicate]

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
There are many reasons that waitFor() doesn't return.
But it usually boils down to the fact that the executed command doesn't quit.
This, again, can have many reasons.
One common reason is that the process produces some output and you don't read from the appropriate streams. This means that the process is blocked as soon as the buffer is full and waits for your process to continue reading. Your process in turn waits for the other process to finish (which it won't because it waits for your process, ...). This is a classical deadlock situation.
You need to continually read from the processes input stream to ensure that it doesn't block.
There's a nice article that explains all the pitfalls of Runtime.exec() and shows ways around them called "When Runtime.exec() won't" (yes, the article is from 2000, but the content still applies!)
It appears you are not reading the output before waiting for it to finish. This is fine only if the output doesn't fill the buffer. If it does, it will wait until you read the output, catch-22.
Perhaps you have some errors which you are not reading. This would case the application to stop and waitFor to wait forever. A simple way around this is to re-direct the errors to the regular output.
ProcessBuilder pb = new ProcessBuilder("tasklist");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
System.out.println("tasklist: " + line);
process.waitFor();
Also from Java doc:
java.lang
Class Process
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.
Fail to clear the buffer of input stream (which pipes to the output stream of subprocess)
from Process may lead to a subprocess blocking.
Try this:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
I would like to add something to the previous answers but since I don't have the rep to comment, I will just add an answer. This is directed towards android users which are programming in Java.
Per the post from RollingBoy, this code almost worked for me:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
In my case, the waitFor() was not releasing because I was executing a statement with no return ("ip adddr flush eth0"). An easy way to fix this is to simply ensure you always return something in your statement. For me, that meant executing the following: "ip adddr flush eth0 && echo done". You can read the buffer all day, but if there is nothing ever returned, your thread will never release its wait.
Hope that helps someone!
There are several possibilities:
You haven't consumed all the output on the process's stdout.
You haven't consumed all the output on the process's stderr.
The process is waiting for input from you and you haven't provided it, or you haven't closed the process's stdin.
The process is spinning in a hard loop.
As others have mentioned you have to consume stderr and stdout.
Compared to the other answers, since Java 1.7 it is even more easy. You do not have to create threads yourself anymore to read stderr and stdout.
Just use the ProcessBuilder and use the methods redirectOutput in combination with either redirectError or redirectErrorStream.
String directory = "/working/dir";
File out = new File(...); // File to write stdout to
File err = new File(...); // File to write stderr to
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out); // Redirect stdout to file
if(out == err) {
builder.redirectErrorStream(true); // Combine stderr into stdout
} else {
builder.redirectError(err); // Redirect stderr to file
}
Process process = builder.start();
For the same reason you can also use inheritIO() to map Java console with external app console like:
ProcessBuilder pb = new ProcessBuilder(appPath, arguments);
pb.directory(new File(appFile.getParent()));
pb.inheritIO();
Process process = pb.start();
int success = process.waitFor();
You should try consume output and error in the same while
private void runCMD(String CMD) throws IOException, InterruptedException {
System.out.println("Standard output: " + CMD);
Process process = Runtime.getRuntime().exec(CMD);
// Get input streams
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = "";
String newLineCharacter = System.getProperty("line.separator");
boolean isOutReady = false;
boolean isErrorReady = false;
boolean isProcessAlive = false;
boolean isErrorOut = true;
boolean isErrorError = true;
System.out.println("Read command ");
while (process.isAlive()) {
//Read the stdOut
do {
isOutReady = stdInput.ready();
//System.out.println("OUT READY " + isOutReady);
isErrorOut = true;
isErrorError = true;
if (isOutReady) {
line = stdInput.readLine();
isErrorOut = false;
System.out.println("=====================================================================================" + line + newLineCharacter);
}
isErrorReady = stdError.ready();
//System.out.println("ERROR READY " + isErrorReady);
if (isErrorReady) {
line = stdError.readLine();
isErrorError = false;
System.out.println("ERROR::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" + line + newLineCharacter);
}
isProcessAlive = process.isAlive();
//System.out.println("Process Alive " + isProcessAlive);
if (!isProcessAlive) {
System.out.println(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Process DIE " + line + newLineCharacter);
line = null;
isErrorError = false;
process.waitFor(1000, TimeUnit.MILLISECONDS);
}
} while (line != null);
//Nothing else to read, lets pause for a bit before trying again
System.out.println("PROCESS WAIT FOR");
process.waitFor(100, TimeUnit.MILLISECONDS);
}
System.out.println("Command finished");
}
I think I observed a similar problem: some processes started, seemed to run successfully but never completed. The function waitFor() was waiting forever except if I killed the process in Task Manager.
However, everything worked well in cases the length of the command line was 127 characters or shorter. If long file names are inevitable you may want to use environmental variables, which may allow you keeping the command line string short. You can generate a batch file (using FileWriter) in which you set your environmental variables before calling the program you actually want to run.
The content of such a batch could look like:
set INPUTFILE="C:\Directory 0\Subdirectory 1\AnyFileName"
set OUTPUTFILE="C:\Directory 2\Subdirectory 3\AnotherFileName"
set MYPROG="C:\Directory 4\Subdirectory 5\ExecutableFileName.exe"
%MYPROG% %INPUTFILE% %OUTPUTFILE%
Last step is running this batch file using Runtime.
Here is a method that works for me.
NOTE: There is some code within this method that may not apply to you, so try and ignore it. For example "logStandardOut(...), git-bash, etc".
private String exeShellCommand(String doCommand, String inDir, boolean ignoreErrors) {
logStandardOut("> %s", doCommand);
ProcessBuilder builder = new ProcessBuilder();
StringBuilder stdOut = new StringBuilder();
StringBuilder stdErr = new StringBuilder();
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
if (isWindows) {
String gitBashPathForWindows = "C:\\Program Files\\Git\\bin\\bash";
builder.command(gitBashPathForWindows, "-c", doCommand);
} else {
builder.command("bash", "-c", doCommand);
}
//Do we need to change dirs?
if (inDir != null) {
builder.directory(new File(inDir));
}
//Execute it
Process process = null;
BufferedReader brStdOut;
BufferedReader brStdErr;
try {
//Start the command line process
process = builder.start();
//This hangs on a large file
// https://stackoverflow.com/questions/5483830/process-waitfor-never-returns
//exitCode = process.waitFor();
//This will have both StdIn and StdErr
brStdOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
brStdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//Get the process output
String line = null;
String newLineCharacter = System.getProperty("line.separator");
while (process.isAlive()) {
//Read the stdOut
while ((line = brStdOut.readLine()) != null) {
stdOut.append(line + newLineCharacter);
}
//Read the stdErr
while ((line = brStdErr.readLine()) != null) {
stdErr.append(line + newLineCharacter);
}
//Nothing else to read, lets pause for a bit before trying again
process.waitFor(100, TimeUnit.MILLISECONDS);
}
//Read anything left, after the process exited
while ((line = brStdOut.readLine()) != null) {
stdOut.append(line + newLineCharacter);
}
//Read anything left, after the process exited
while ((line = brStdErr.readLine()) != null) {
stdErr.append(line + newLineCharacter);
}
//cleanup
if (brStdOut != null) {
brStdOut.close();
}
if (brStdErr != null) {
brStdOut.close();
}
//Log non-zero exit values
if (!ignoreErrors && process.exitValue() != 0) {
String exMsg = String.format("%s%nprocess.exitValue=%s", stdErr, process.exitValue());
throw new ExecuteCommandException(exMsg);
}
} catch (ExecuteCommandException e) {
throw e;
} catch (Exception e) {
throw new ExecuteCommandException(stdErr.toString(), e);
} finally {
//Log the results
logStandardOut(stdOut.toString());
logStandardError(stdErr.toString());
}
return stdOut.toString();
}
Asynchronous reading of stream combined with avoiding Wait with a timeout will solve the problem.
You can find a page explaining this here http://simplebasics.net/.net/process-waitforexit-with-a-timeout-will-not-be-able-to-collect-the-output-message/
public static void main(String[] args) throws PyException, IOException, InterruptedException
these should be the exceptions thrown

How to know the ping in ms

I know how to check if a certain site/IP ADDRESS is reachable or not. But I wonder if it's possible to know the response time or the ping in millisecond (ms) for a specific site or an IP address?
Thanks!
It is very much possible :)
Just make sure you have the right permissions(You put this in your AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET" />
My code that works absolutely well.
public String ping(String url) {
String str = "";
try {
java.lang.Process process = Runtime.getRuntime().exec(
"ping -c 1 " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
int i;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
String op[] = new String[64];
String delay[] = new String[8];
while ((i = reader.read(buffer)) > 0)
output.append(buffer, 0, i);
reader.close();
op = output.toString().split("\n");
delay = op[1].split("time=");
// body.append(output.toString()+"\n");
str = delay[1];
Log.i("Pinger", "Ping: " + delay[1]);
} catch (IOException e) {
// body.append("Error\n");
e.printStackTrace();
}
return str;
}
The code above is as simple as you can get.
To call the code...
String str = ping("www.google.com");
//Unecessary but it makes it easier
android.widget.Toast.makeText(this, str, android.widget.Toast.LENGTH_LONG).show();
Java does not have ICMP out of the box. There are three things you can do:
Rely on CLI and use that to get the response from the ping command see here.
Use sockets to calculate latency between sending and receiving information see here.
Use an ICMP library.

Java heap profiling seems to freeze during large file ingestion

I am trying to profile a java 7 application running on a redhat machine. When I run it as follows:
java -agentlib:hprof=cpu=samples,depth=10,monitor=y,thread=y ...
a particular block of code that creates a table-type object by reading a very large gzipped text file line by line completes in about 6 minutes. When I run it like this:
java -agentlib:hprof=heap=sites,depth=10,monitor=y,thread=y ...
the same block takes several orders of magnitude more time to complete (I am estimating something like 24 hours)
Here's the method (part of a class) that reads in the file:
private static void ingestValues()
{
int mSize = 30000;
pairScoresTable = new float[mSize][];
for (int i = 0; i < pairScoresTable.length; i++) {
pairScoresTable[i] = new float[mSize];
Arrays.fill(pairScoresTable[i], fillVal);
}
try
{
BufferedReader bufferedReader =
new BufferedReader(
new InputStreamReader(
new GZIPInputStream(
new FileInputStream(rawPath)), "US-ASCII"));
String line = null;
while((line = bufferedReader.readLine()) != null) { // file has 388661141 lines
Float value = 0.0F;
Integer i = 0;
Integer j = 0;
// extract value, i and j by parsing line...
pairScoresTable[i][j] = value;
pairScoresTable[j][i] = value;
}
bufferedReader.close();
}
catch(Exception e)
{
return;
}
return;
}
So it basically reads a file each line of which is formatted to describe the position of a value in the 2d matrix pairScoresTable.
Why is there such a large difference in execution time? Is there a way to do heap profiling of this code faster without having to refactor it?

put the output of the shell script into a variable in a Java program

Is there a way to get an output from a shell script program into a variable in Java program(not into the output file). The output of my shell script is the database query execution time and I need to assign that time value to a Java variable. (I am calling that shell script from Java program). And then I will need to do some other calculations on those values in Java.
Update to old question
Since Java 7 there is a new class which can easily deal with OS procecces: ProcessBuilder
.Let's assume we need to store the output of ip_conf.bat into a java String. Contents of c:\tmp\ip_conf.bat
#echo off
REM will go to standard output
ipconfig
REM will go to stadnard error
hey there!
You can read the input streams connected to the standard and error outputs of the subprocess:
ProcessBuilder pb = new ProcessBuilder("C:\\tmp\\ip_conf.bat");
Process p = pb.start();
String pOut = "";
try (InputStream stdOut = p.getInputStream();
BufferedInputStream bufferedStdOut = new BufferedInputStream(stdOut);
ByteArrayOutputStream result = new ByteArrayOutputStream()) {
int bytes = 0;
while ((bytes = bufferedStdOut.read()) != -1) {
result.write(bytes);
}
pOut = result.toString(Charset.defaultCharset().toString());
}
System.out.println(pOut);
InputStream stdErr = p.getErrorStream();
// same with the error stream ...
int exit = p.waitFor();
System.out.println("Subprocess exited with " + exit);
Below is the program that will help you store the full output of any script or any command into String object.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecuteShellComand {
public static void main(String[] args) {
ExecuteShellComand obj = new ExecuteShellComand();
String output = obj.executeCommand("sh /opt/yourScriptLocation/Script.sh");
System.out.println(output);
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
I just google it and there is a nice tutorial, full of examples here : http://www.mkyong.com/java/how-to-execute-shell-command-from-java/
I know people prefere copy/paste but let's respect other people's work and go on their website :p

Force the read() method to read a minimum no of characters

I am trying to do telnet to a router with expect kind of implementation.
My code is as follows for the socket communication is as follows,
server = "my-server-ip-domain-here";
socket = new Socket();
socket.connect(new InetSocketAddress(server, 23), 10000);//Will wait for 10 seconds
socket.setKeepAlive(true);
socket.setSoTimeout(10000);
expectBuffer = new StringBuilder();
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream(), true);
My send implementation is as follows,
public static void send(String cmd) {
pw.print(cmd + "\r");
pw.flush();
}
My expect implementation is as follows,
public static String expect(String expectString) {
try {
int c = 0;
char[] buf = new char[4096];
//Here c will return the no. of chars read
while ((c = br.read(buf)) != -1) {
String tmp = "";
//converting that char array to String
for (int i = 0; i < c; i++) {
//Printing that character
System.out.print(buf[i]);
tmp += buf[i];
}
expectBuffer.append(tmp).append(NEW_LINE);
if (expectBuffer.toString().contains(expectString)) {
break;
}
}
String expBuff = expectBuffer.toString();
expectBuffer.setLength(0);
// System.out.println(expBuff);
return expBuff;
} catch (Exception e) {
System.out.println(e);
return "";
}
}
The problem i am facing is the no. of characters read by BufferedReader each time.
i.e. Each time I have to send some commands to the router and that is also being read by BufferedReader.
For eg.
send ("commandABC");
expect(prompt);
send ("command-efg");
expect(prompt);
send ("commandHij");
expect(prompt);
Based on the commands I am sending, it will show some output. Whatever I am sending, that is also being read and unfortunately, it is getting printed in a separate manner.
Like as below.
com
mandABC
<command output here>
command-
efg
<command output here>
commandHij
<command output here>
As i pointed out above, only the commands, whichever I am sending are getting printed in separate manner.
I have checked the no. of char read at that time and found that it is ranging from 2-10.
That is why it is getting printed in that manner.
Is there anyway to restrict the read at least a minimum of 100 chars?
Thanks in advance.
If you want to wait until you've read a full line of text, try bf.readLine() (you'd need to make sure each command was terminated by '\n'
If you want to make sure you've read a certain number of characters (say 100) before continuing processing, use a loop:
char buffer[128];
for (int charsRead = 0; charsRead < 100; ) {
charsRead += bf.read(buffer, charsRead, (100 - charsRead));
}
Note the (verbosified) syntax for bf.read():
bf.read(buffer, offset_size, max_to_read)
Passing charsRead as the offset size means each block of chars read will be stored right after the previously read ones. Passing (100 - charsRead) as max_to_read limits the total chars you read.
Source: API ref http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html#read(char[],%20int,%20int

Categories

Resources