TCPDump-Buffer上的ReadLine有时会阻塞直到kill tcpdump

时间:2011-04-19 10:18:51

标签: java android tcpdump

我在Android-Application中使用TCPDump时遇到问题。 它应该逐行读取tcpdump的输出并在我的Application中处理它。
问题是:
有时代码工作正常,它会立即读取捕获的数据包。但有时,ReadLine会阻塞,直到我从Linux-Console(killall tcpdump)中杀死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);
            }

        }

    }

}

}

2 个答案:

答案 0 :(得分:3)

由于发送到管道的输出通常是块缓冲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";

答案 1 :(得分:0)

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

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

必须将线程内的run方法更改为在输出文件中读取:

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代码中的regexp实现相同的操作。

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