【问题标题】:ReadLine on TCPDump-Buffer sometimes blocks until kill tcpdumpTCPDump-Buffer 上的 ReadLine 有时会阻塞,直到杀死 tcpdump
【发布时间】:2011-04-19 10:18:50
【问题描述】:

我在使用我的 Android 应用程序中的 TCPDump 时遇到问题。 它应该逐行读取 tcpdump 的输出并在我的应用程序中处理它。
问题是:
有时代码运行良好,它会立即读取捕获的数据包。但有时,ReadLine 会阻塞,直到我从 Linux 控制台终止 tcpdump 进程(killall tcpdump)。之后,我的循环会针对每一行(有时是 10 行,有时是 1 或 2 行)进行处理——这意味着 readLine 应该可以工作,但没有。
我读过类似的问题,但没有找到任何解决此问题的方法...
谢谢!!

public class ListenActivity extends Activity {

static ArrayList<Packet> packetBuffer = new ArrayList<Packet>();
static Process tcpDumpProcess = null;
static ListenThread thread = null;
public static final String TCPDUMP_COMMAND = "tcpdump -A -s0 | grep -i -e 'Cookie'\n";

private InputStream  inputStream = null;
private OutputStream outputStream = null;

@Override
protected void onStart() {
    super.onStart();
    try {
        tcpDumpProcess = new ProcessBuilder().command("su").redirectErrorStream(true).start();
        inputStream = tcpDumpProcess.getInputStream();
        outputStream = tcpDumpProcess.getOutputStream();
        outputStream.write(TCPDUMP_COMMAND.getBytes("ASCII"));
    } catch (Exception e) {
        Log.e("FSE", "", e);
    }
    thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
    thread.start();
}

private class ListenThread extends Thread {

    public ListenThread(BufferedReader reader) {
        this.reader = reader;
    }

    private BufferedReader reader = null;

    @Override
    public void run() {

        reader = new BufferedReader(new InputStreamReader(inputStream));
        while (true) {
            try {                   
                String received = reader.readLine();
                Log.d("FS", received);
                Packet pReceived = Packet.analyze(received);
                if (pReceived != null) {
                    packetBuffer.add(pReceived);
                }
            } catch (Exception e) {
                Log.e("FSE", "", e);
            }

        }

    }

}

}

【问题讨论】:

  • 您不直接使用jnetpcap 有什么原因吗?阅读另一个进程的输出感觉像是解决问题的漫长道路。
  • 老实说,我不知道 jnetpcap :-) 这看起来确实是我需要的...我正在深入研究它并尝试找出它是否为 Android-ARM 成功编译。谢谢!!

标签: java android tcpdump


【解决方案1】:

因为发送到管道的输出通常是块缓冲,所以tcpdump 进程grep 进程都将等待,直到它们收到足够的数据麻烦将它发送到你的程序。不过你很幸运,你选择使用的两个程序都准备好修改它们的缓冲区行为(在内部使用 setvbuf(3) 函数,以防你对细节感到好奇):

对于tcpdump(8)

   -l     Make stdout line buffered.  Useful if you want to see
          the data while capturing it.  E.g.,
          ``tcpdump  -l  |  tee dat'' or ``tcpdump  -l   >
          dat  &  tail  -f  dat''.

对于grep(1)

   --line-buffered
          Use line buffering on output.  This can cause a
          performance penalty.

试试这个:

"tcpdump -l -A -s0 | grep --line-buffered -i -e 'Cookie'\n";

【讨论】:

  • 嗯 - 这听起来正是我的问题(块缓冲) - 但不幸的是 Android 上的 grep 没有 --line-buffered 选项...... argh .是否有可能减少此进程的块大小或完全禁用缓冲?
  • @andreas911,如果您要运行诸如pty(来自Advanced Programming in the Unix Environment)之类的程序,该程序会创建一个用于运行任意程序的伪终端,您可以欺骗grep 认为它的output 是一个终端,因此应该使用行缓冲输出。提供您自己的grep 程序或在您的Java 程序中执行过滤可能会更容易。假设 jnetpcap 完全不是更好的答案。 :)
【解决方案2】:

我不明白为什么,但即使使用 -l 选项,如果您读取运行 tcpdump 的进程的标准输出,缓冲区也会太大。 我通过将 TcpDump 的输出重定向到一个文件并在另一个线程中读取这个文件来解决这个问题。 TcpDump 命令应该是这样的:

tcpdump -l-A -s0 > /data/local/output.txt

你的线程内的运行方法必须改变以读取输出文件:

File dumpedFile = new File("/data/local/output.txt");
//open a reader on the tcpdump output file
BufferedReader reader = new BufferedReader(new FileReader(dumpedFile));
String temp = new String();
//The while loop is broken if the thread is interrupted   
while (!Thread.interrupted()) {    
    temp = reader.readLine();
    if (temp!=null) {
        Log.e("READER",new String(temp));    
    }
}

我不完全知道您想用 grep 做什么,但我认为在 Java 代码中使用正则表达式可以实现相同的操作。

您还应该知道,TcpDump 的进程永远不会结束,因此当您的活动暂停或破坏时,您必须终止它。 您可以查看here 到我的博客文章,我解释了我的整个代码来启动/停止 tcpdump。

【讨论】:

  • 欢迎来到 Stack Overflow。请注意,SO 旨在成为优秀问题和答案的存储库,而不是链接交换服务。请在以后将您博客文章的相关部分复制到您的答案中。
猜你喜欢
  • 2018-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-05
  • 2018-09-26
  • 2013-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多