2011-04-19 85 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