2011-04-19 24 views
1

我的Android应用程序使用TCPDump时出现问题。 它应该从tcpdump逐行读取输出并在我的应用程序中处理它。
问题是:
有时代码工作正常,它立即读取捕获的数据包。但有时,ReadLine会阻塞,直到我从Linux控制台(killall tcpdump)中终止tcpdump进程。这样做后,我的循环是处理每一行(有时10,有时1或2) - 这意味着,readLine应该工作,但没有。
我读了类似的问题,但没有找到任何解决方案,这个问题...
谢谢!TCPDump-Buffer上的ReadLine有时会阻塞直到kill tcpdump

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

     } 

    } 

} 

}

+0

你有没有直接使用[jnetpcap](http://jnetpcap.com/)的原因?读取另一个进程的输出结果似乎要解决您的问题还有很长的路要走。 – sarnold 2011-04-19 10:21:11

+0

说实话,我并不了解jnetpcap :-)这看起来像我需要的东西......我正在深入研究它,并尝试查明它是否已成功编译为Android-ARM。谢谢!! – andreas911 2011-04-19 12:46:08

回答

2

因为发送到管道输出通常是块缓冲,二者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"; 
+0

好吧 - 这听起来像是我的问题(块缓冲) - 但不幸的是,Android上的grep没有-line-buffered选项... * argh *。在这个过程中是否有可能减少块大小或禁用缓冲? – andreas911 2011-04-19 12:39:44

+0

@ andreas911,如果您要运行一个程序,如'pty'(来自[Unix环境中的高级编程](http://www.apuebook.com/)),该程序创建一个用于运行任意程序的伪终端,你可以欺骗'grep'来认为它的输出是一个终端,因此应该使用行缓冲输出。只需要提供自己的'grep'程序或者在Java程序中执行过滤可能会更容易。假设jnetpcap并不是最好的答案。 :) – sarnold 2011-04-19 23:18:48

0

我不明白为什么,但即使使用-l选项,如果读取运行tcpdump的进程的标准输出,缓冲区也会太大。 我通过将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代码中使用正则表达式实现相同的操作。

你也应该知道TcpDump的过程永远不会结束,所以当你的活动暂停或破坏时你必须杀死它。 你可以看我的博客文章here,我解释我的整个代码来启动/停止tcpdump。

+1

欢迎来到堆栈溢出。请注意,SO旨在成为优秀问题和答案的存储库,而不是链接交换服务。请将您的博客帖子的相关部分在未来复制到您的答案中。 – sarnold 2011-06-01 23:30:19