2015-02-10 46 views
1

好吧,所以我試圖從java代碼讀取c二進制文件的輸出,我無法確定通信通道是阻塞還是非阻塞。從java中執行C二進制文件和從進程的輸出流中讀取

的設置是這樣的:

  1. 一個Java類(A.java)運行

  2. A.java運行使用Runtime.getRuntime().exec("B.o")一個C二元(B.o)。此時我有Process對象(通過的Runtime.exec返回)

  3. A.java使用一個BufferedReader

  4. A.java輸出從輸入讀出的數據從所述處理對象的輸入流中讀取流式傳輸到一個文件(output.txt

的柏二進制簡單的打印用printf函數調用隨機線。

現在,如果我運行上面的設置,我會收到由B.o發送的所有數據完美無瑕。然後爲了測試(阻塞/非阻塞的事情),我在每次從B.o的Process對象的輸入流讀取之後將A.java更改爲睡眠5毫秒。事實證明,現在我沒有收到由B.o發送的A.java的完整數據。這表明正在使用的通信信道是非阻塞的(根據我的理解)。

然後,爲了確保,我開始查看java的源代碼,看看我是否正確。到目前爲止,我發現了以下內容:

Runtime.getRuntime().exec(...)的每個呼叫都以forkAndExec()方法結束於ProcessImpl_md.c。在ProcessImpl_md.c中,執行該命令,創建一個進程,併爲通信設置PIPES(使用c中的管道函數調用)。我找不到源代碼中的任何地方,其中PIPES被設置爲非阻塞模式(如我的代碼所示)。我假設PIPES默認爲阻塞狀態。

我知道這是一個非常糟糕的方法來檢查我想檢查。我認爲,我在這裏深深地陷入了困境,我只是無用而已。

任何人都可以點我在正確的方向,或者告訴我:

  1. PIPES通過Java運行時API創建進程的被阻塞或非阻塞?

  2. 當我從輸入流中讀取A.java後,爲什麼沒有收到所有數據? (假設是管道阻塞)

  3. 任何非程序化的方法(即我沒有改變java和等!的源代碼),以找出是否PIPES的過程中被封鎖還是非阻塞?

謝謝。

編輯:(添加的代碼)

以下是不實際的(甚至編譯)代碼,但它顯示了什麼,我試圖做的。

「B.O」 來源:

#include <stdio.h> 
void main(int argc, char*argv[]){ 
    int a = 0; 
    for(; a<9000000; a++){ 
     printf("%s", argv[1]); 
    } 
} 

「A.java」 來源:

<java imports> 
public class A{ 
    public static void main(String[] args) throws Exception{ 
     Process p = Runtime.getRuntime().exec("./B.o"); 
     BufferedReader br = new 
      BufferedReader(new InputStreamReader(p.getInputStream())); 
     int a = 0; 
     while(br.readLine() != null){ 
      a++; 
      Thread.sleep(5);//data missed if this line not commented out 
     } 
     br.close(); 
     System.out.println(a); 
    } 
} 

請檢查我的答案。無我問題。

+0

我會避免使用可執行文件的擴展名*(* .o')。該擴展通常用於目標文件。 – 2015-02-10 17:33:33

+0

睡眠不應該改變你從BufferedReader中包裝的InputStream獲得的輸入。 「非阻塞」讀取並不意味着您跳過輸入以獲取管道中最近的寫入。也就是說,目前尚不清楚爲什麼你要觀察跳過的數據。你能發佈相關的代碼嗎? – 2015-02-10 17:45:56

+1

真的是「隨機」行嗎?你永遠不知道是否有人失蹤。 – laune 2015-02-10 17:49:50

回答

3

Java和外部程序之間的通信通道(有三個,一個從Java到本地,兩個回來)在阻塞模式還是非阻塞模式下操作與是否所有數據都將成功無直接關係通過每個傳輸。同樣,讀取請求之間的延遲與所有數據是否將被成功傳輸都無直接關係,無論您在java.lang.Process的特定實現中的阻塞與非阻塞I/O如何。

真的,你的努力探討阻塞主場迎戰無阻塞的進程間I/O都是徒勞的,因爲提供給您的Java程序的I/O接口是基於InputStreamOutputStream,只爲阻擋提供I/O。即使在一些低級別的實現中涉及非阻塞I/O,我也想不出任何方式讓您的程序檢測到這一點。

對於您的具體問題,但是:

通過Java運行時API創建進程的管道阻塞或非阻塞?

他們可能是,但他們更有可能阻止,因爲它更好地匹配呈現給Process用戶的界面。

當我從輸入流中讀取A.java睡眠時,爲什麼沒有收到所有的數據? (假設PIPE被阻塞)

我只能推測,但問題可能在外部程序中。它的輸出緩衝區填滿後可能會進入休眠狀態,沒有任何事會喚醒它。如果您的Java程序沒有將數據發送到外部程序,那麼調用myProcess.getOutputStream().close()可能會有幫助。無論如何,一旦你寫下了你將要寫的所有內容,關閉這個流是一個好主意。

任何非編程方式(即我不需要更改java等的源代碼)來確定進程的PIPES是阻塞的還是非阻塞的?

可能你可以運行虛擬機下strace或連接一個本地調試器,並以這種方式分析虛擬機的行爲。如果你的意思是從Java內部做到這一點,那麼答案是一個響亮的「否」。您的Java程序將在所有情況下看到阻止行爲,因爲InputStreamOutputStream的合約要求它。

+0

感謝您的詳細回覆。如果B.o(c二進制)的管道的寫入結束是阻塞還是非阻塞,您能否讓我進一步知道?因爲我能想到的所有數據沒有通過的唯一原因是管道寫入緩衝區(在B.o的末尾)變滿了(因爲我正在讓我的java代碼進入睡眠狀態,從而導致緩衝區延遲清空)。這會導致溢出的數據被丟棄。但是,爲了實現這一點,管道必須是非阻塞的? – Undefined 2015-02-11 05:45:50

+0

Blocking vs. non-blocking與read()和write()調用是否會在無法立即傳輸任何數據時會阻塞有關。在任何情況下,您都不應期望管道丟失數據,無論阻塞與非阻塞模式如何。如果您沒有收到您期望從'B.o'獲得的所有數據,那幾乎肯定是因爲'B.o'是錯誤的。你的數據首先不會進入管道。 – 2015-02-11 15:09:33

+0

請注意,除非指定了剛好一個字節並且文件描述符在阻塞模式下打開,否則不能保證成功執行'read()'和'write()'syscalls傳輸所請求的全部字節數。除了單字節特殊情況外,不依賴於阻止模式。假設這些調用將傳輸所請求的全部字節數是一個常見錯誤,但只有在您直接調用這些函數時才需要關注。 – 2015-02-11 15:20:02

0

我犯了一個大錯,完全離開了基地。發佈這個答案來澄清事情(儘管我想完全刪除這個問題)。我想知道來自Java代碼的C二進制文件之間的通信通道是阻塞的還是非阻塞的。我提到,當從創建的進程(C代碼)的輸入流中讀取我的java代碼後,數據丟失了。數據並沒有因此而丟失。實際上,我在Java代碼中放置了一個計時器,之後終止C二進制文件的進程。由於PIPES被阻塞,所以在定時器過期之前無法接收所有數據。我誤解了這種數據丟失意味着PIPES是非阻塞的。通過在創建的C二進制進程上運行STRACE來確認這一點。寫入系統調用時沒有EAGAIN錯誤。我的錯。但非常感謝大家抽出時間作出迴應。