如何运行 tshark in Java 实时获取数据包?

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

我在 Java 中遇到 运行ning tshark 的问题。数据包似乎是批量到达的,而不是真正实时的(当 运行 来自终端时会发生这种情况)。 我尝试了几种不同的方法:

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...

还尝试使用 InputStream 的 available() 方法,如 What does InputStream.available() do in Java?

中所示

我还使用以下代码尝试了 NuProcess 库:

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 的方法有效。数据包总是到达,就像缓冲一样,只有当大约 50 个被嗅探时。

您是否知道为什么会发生这种情况以及如何解决?这很令人沮丧。我花了很多时间在 SO 上查看类似的问题,但是 none 对他们有帮助。

您在我的代码中看到任何错误吗?它适用于您的情况吗?

我 运行 进行了一些测试,以了解 BufferedReader 与仅使用输入流相比会完成多少缓冲。

        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();
        }

我试图找到一个可以尽可能快地保持打印的命令,这样任何延迟都是由于缓冲 and/or ProcessBuilder 而不是命令本身造成的。这是结果图。

尽管我使用了名为 DebugPlot 的 Netbeans 插件,但您可以使用 excel 绘制 csv 文件。原始和缓冲之间没有太大区别。两者都是突发的,大多数读取时间不到 1 微秒,间隔为 10 到 50 毫秒的峰值。该图的比例以纳秒为单位,因此 5E7 的顶部是 50 毫秒或 0.05 秒。如果您测试并获得类似的结果,也许这是流程构建器可以做的最好的事情。如果使用 tshark 得到的结果比其他命令差得多,也许可以选择 tshark,或者数据包本身是突发的。

正如 tshark 手册页所说:

   −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.

使用 -l 命令行参数尝试 运行 tshark。