2012-07-27 85 views
1
發送命令到一個子進程

我試圖寫omxplayer一個遠程控制程序對我rasperry皮通過管道/ DUP2用C

我能得到omxplayer運行在一個子進程好,但我不知道似乎能夠使管道正常工作,以實際發送命令到子進程。

int fd_pipe[2]; 
pipe (fd_pipe); 

while(1) { // main accept() loop 

    printf("server: got connection from %s\n", s); 

    /* Attempt to fork and check for errors */ 
    if((pid=fork()) == -1){ 
     fprintf(stderr,"Fork error. Exiting.\n"); /* something went wrong */ 
     exit(1); 
    } 

    if (pid==0) 
    { // this is the child process 
     dup2(0, fd_pipe[0]); 
     close(fd_pipe[1]); 


     if(execl("/usr/bin/top","top",NULL) == -1){ 
      fprintf(stderr,"execl Error!"); 
      exit(1); 
     } 

     //try and send command here 
     write(fd_pipe[0], "q", 1); 

     exit(0); 

    } else { 

     close(new_fd); // parent doesn't need this 
     dup2(1, fd_pipe[1]); 

     //try and send here too 
     write(fd_pipe[0], "q", 1); 
    } 
} 

當我與頂級測試和運行程序,我可以看到上面的輸出出現在終端窗口,我可以在窗口中看到的q命令,但它看起來像它的將父進程,而比孩子。我是否在管道上做了錯誤的事情,或者不可能將命令發送到派生的子進程?

我試圖改變孩子DUP2語句從管道複製到標準輸入

 { // this is the child process 
     dup2(fd_pipe[0], 0); 

但隨後頂部未能啓動失敗的tty得到消息

回答

0

要與預計將程序交互能夠操縱一個終端,你應該使用僞tty。這將避免failed tty get錯誤。

/*...*/ 
#include <pty.h> 

void do_child() { 
    if (execlp("top", "top", (const char *)0) < 0) { 
     perror("exec top"); 
     exit(EXIT_FAILURE); 
    } 
    /* NOTREACHED */ 
} 

void do_parent (int fd, pid_t p) { 
    sleep(5); 
    char r; 
    write(fd, "q", 1); 
    while (read(fd, &r, 1) > 0) { write(1, &r, 1); } 
    waitpid(p, 0, 0); 
    close(fd); 
} 

int main() { 
    int fd; 
    pid_t p = forkpty(&fd, 0, 0, 0); 
    switch (p) { 
    case 0: do_child(); 
      /* NOTREACHED */ 
    case -1: perror("forkpty"); 
      exit(EXIT_FAILURE); 
    default: break; 
    } 
    do_parent(fd, p); 
    return 0; 
} 

注意forkpty不是POSIX,但上可用的BSD UNIX和Linux的味道的接口。

您可以在批處理模式下執行top,但不能使用命令退出。你必須殺死它。

void do_child() { 
    if (execlp("top", "top", "-b", (const char *)0) < 0) { 
     perror("exec top"); 
     exit(EXIT_FAILURE); 
    } 
    /* NOT REACHED */ 
} 

void do_parent (pid_t p) { 
    sleep(5); 
    if (kill(p, SIGINT) < 0) { 
     perror("kill"); 
     exit(EXIT_FAILURE); 
    } 
    waitpid(p, 0, 0); 
} 

int main() { 
    pid_t p; 
    switch ((p = fork())) { 
    case 0: do_child(); 
    case -1: perror("fork"); exit(EXIT_FAILURE); 
    default: break; 
    } 
    do_parent(p); 
    return 0; 
} 

雖然在批處理模式下運行將允許你用一個簡單的通話打開進程(如popen的MUX建議),除非該調用返回兒童的進程id,你將不能夠殺死它(不執行pkill,或挖掘進程表找到正確的子進程殺死)。

我想你對如何使用dup2有一些困​​惑。手冊頁使用術語oldfdnewfd,這意味着oldfd將變爲newfd。爲了說明,這裏有一個簡單的程序,它將stdout和stderr重定向到日誌文件,調用函數,然後恢復stdout和stderr。

void do_something() { 
    fputs("Error message\n", stderr); 
    puts("This is regular output."); 
    fputs("Error message\n", stderr); 
    puts("This is regular output."); 
} 

int main() { 
    int fd = creat("/tmp/output.log", 0664); 
    int outfd = dup(fileno(stdout)); 
    int errfd = dup(fileno(stderr)); 
    fflush(stdout); 
    fflush(stderr); 
    dup2(fd, fileno(stdout)); 
    dup2(fd, fileno(stderr)); 
    setlinebuf(stdout); 

    do_something(); 

    fflush(stdout); 
    fflush(stderr); 
    dup2(outfd, fileno(stdout)); 
    dup2(errfd, fileno(stderr)); 
    close(outfd); 
    close(errfd); 

    fputs("Error to the screen\n", stderr); 
    puts("Regular output to screen"); 
    fputs("Error to the screen\n", stderr); 
    puts("Regular output to screen"); 

    return 0; 
} 

由於MUX指出的那樣,你的程序被寫入管錯誤的一端。 pipe命令返回一對單向文件描述符,其中可以從fd_pipe[0]中讀取任何寫入fd_pipe[1]的內容。

+0

謝謝user315052和@mux - oops我的意思是說我正在寫給fd_pipe [1]。我以最高要求爲例,而不是最終要求。我正嘗試使用它在子進程中運行名爲omxplayer的媒體播放器,然後能夠向該進程發送命令。我已經從子進程中刪除寫入,並且只寫(fd_pipe [1],「q」,1); – Karl 2012-07-30 12:21:57

+0

@Karl:所以,你沒有真正嘗試使用僞tty解決方案?爲什麼不? – jxh 2012-07-30 14:27:26

+0

我試圖但是我有麻煩尋找它的圖書館。我已經安裝了pty.h,但是當我嘗試編譯時,我得到了對'forkpty'錯誤的未定義引用。所以我試圖鏈接-l/usr/lib/libutils,但是它的報告:/ usr/bin/ld:找不到-l/usr/lib/libutils – Karl 2012-07-30 15:01:01