2011-12-27 163 views
3

基本上我想在C(和無緩衝)與此相同的bash腳本做:C:如何重定向命名管道標準輸入/輸出子進程的

#!/bin/sh 
cat ./fifo_in | myprogram > ./fifo_out 

換句話說,我想exec「myprogram」並將其stdin和stdout重定向到之前創建的兩個管道。

另一個程序是將數據送入fifo_in並讀出fifo_out。

當然,它會很容易從./fifo_in剛讀,緩衝它在父和寫入myprogram的標準輸入(和反向stdout和./fifo_out),但我認爲有可能是一個辦法,讓「myprogram」讀/寫直接從/到fifos而不在父進程中緩衝。

編輯:

尤金的答案似乎是正確的,但我不能得到它的工作。

我用在C端這個功能,這似乎是正確的對我說:

pid_t execpipes(const char *wd, const char *command, const char *pipename) 
{ 
char pipename_in[FALK_NAMESIZE]; 
char pipename_out[FALK_NAMESIZE]; 
strcpy(pipename_in, FALKPATH); 
strcat(pipename_in, "/"); 
strcat(pipename_in, FALK_FIFO_PATH); 
strcat(pipename_in, "/"); 
strncat(pipename_in, pipename, FALK_NAMESIZE-2); 
strcpy(pipename_out, pipename_in); 
strcat(pipename_out, "R"); 

pid_t pid; 
pid = fork(); 
if (pid < 0) 
{ //Error occured 
    perror("fork"); 
    exit(1); 
} 
if (pid == 0) 
{ 
    chdir(wd); 
    d("execpipes: pipename_in=\"%s\"\n", pipename_in); 
    d("   pipename_out=\"%s\"\n", pipename_out); 
    freopen(pipename_in,"r",stdin); 
    freopen(pipename_out,"w",stdout); 

    d("execpipes: command=\"%s\"\n", command); 

    execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster 
    // Should never get here 
    perror("execl"); 
    exit(1); 
} 
return pid; 
} 

我讀寫從PHP腳本管道(僅相關部分發布):

$pipe_in = fopen($fp.$pipename, "w"); 
$DEBUG .= "Write to pipe_in\n"; 
$ret = fwrite($pipe_in, $in); 

$pipe_out = fopen($fp.$pipename.'R', "r"); 
$DEBUG .= "Read from pipe_out\n"; 
$atext = fread($pipe_out, 200000); // Program hangs here 

程序啓動正確,通過$pipe_in正確接收輸入,正確處理數據並且(因爲它運行良好很多個月)我假設它將數據正確地輸出到標準輸出,但是當我嘗試從$pipe_out讀取數據時,它掛起。我知道管道本身設置正確,因爲如果我不打開$pipe_out,程序沒有得到任何輸入 - 這是有道理的,因爲沒有$pipe_out的閱讀器,因此管道不完整。所以我可以打開$pipe_out,但我無法從中讀取任何內容,這很奇怪。

EDIT2:

計劃現在工作,感謝你們 - 出於某種原因,第一管有,然後才能從第二管道讀取被關閉:

$pipe_in = fopen($fp.$pipename, "w"); 
$pipe_out = fopen($fp.$pipename.'R', "r"); 
$DEBUG .= "Write to pipe_in\n"; 
$ret = fwrite($pipe_in, $in); 
fclose($pipe_in); 

$DEBUG .= "Read from pipe_out\n"; 
$atext = fread($pipe_out, 200000); 
fclose($pipe_out); 

unlink($fp.$pipename); 
unlink($fp.$pipename.'R'); 
+0

你是在寫'myprogram'或者其他一些「調用」'myprogram'的程序嗎? – pmg 2011-12-27 16:04:28

+1

任何濫用「貓」的理由?爲什麼不使用:'myprogram < ./fifo_in >。/ fifo_out'? – 2011-12-27 16:22:12

+0

沒有理由使用貓,bash腳本只是爲了澄清C程序應該做什麼。 – Robby75 2011-12-28 07:20:52

回答

2

我寫myprogram小包裝,T帽子確實

freopen("./fifo_in","r",stdin) 
freopen("./fifo_out","w",stdout) 

(Ofcourse不是恆定的路徑!),然後execve的myprogram

+0

謝謝,我在C端使用了它(請參閱上面的編輯),但系統在嘗試從fifo_out讀取時掛起。 – Robby75 2011-12-28 12:29:28

0

Korn shell的支持協進程,這是我想有效地做什麼你問:從管道讀取和寫入到一個管道(可stdout和一個C程序的標準輸入)

http://www.dartmouth.edu/~rc/classes/ksh/coprocesses.html 
+0

但是你如何從C編程實現? – 2011-12-27 16:28:42

+0

我以爲OP想要使用現有的C代碼並想要一個shell封裝器。 – 2011-12-27 21:44:34

0

如何

myprogram <./fifo_in> ./fifo_out 

至於擺脫緩衝:由於你的程序直接讀/寫管道,緩衝不應該傷害你。

重要的一點是,寫入fifo_in的過程應該正確刷新,因此您不必等待。輸出也是如此:一旦「工作單位」完成,請刷新您的stdout,這將使讀取輸出管道的任何人都可以使用數據。

但是您不能在myprogram中做任何事情來讓fifo_in的作者刷新其緩衝區。

[編輯]從C中做到這一點(沒有殼的幫助下),使用這樣的代碼:

- Put the names of the two pipes into local variables on the stack 
- Call `fork()`. If that returns '0', then open the two fifos with `freopen()` [like Eugen suggested][1] 
- Call `execve` to launch the real exec. 

這是(簡而言之),當它運行的是什麼殼做的命令。確保父進程(fork()返回PID!= 0)處理信號SIGCHLD

+0

這就是你如何從shell中完成的。但是OP在問他如何從他自己的流程中做到這一點,使用C. – 2011-12-27 16:29:17

0

也許您正在尋找一個named pipe?例如:

mkfifo fifo_in 

作爲測試存根my_program.c,讀取經由fifo_in所緩衝stdin

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(void) { 
    char buf[80]; 
    if (!freopen("./fifo_in", "r", stdin)) { 
     perror("freopen"); 
     exit(EXIT_FAILURE); 
    } 
    while (!ferror(stdin)) { 
     while (fgets(buf, sizeof buf, stdin)) 
     fputs(buf, stdout); 
     sleep(1); 
    } 
    return 0; 
} 

然後作爲寫入器的測試,使用bash殼:

for x in {1..10}; do 
    echo $x 
    echo $x >> fifo_in 
    sleep 1 
done 

備註:

  • 我寧願使用無緩衝的I/O。
  • 作者,至少在我的機器上,阻止,直到有讀者。
  • 在本示例中,讀者無法分辨作者何時完成。
相關問題