2015-08-09 74 views
-1

我想實現使用c語言的管道。 我通過創建子進程在c中實現管道,但它不工作

繼執行由管道分隔每個命令的循環是我的代碼:

int main(int argc, char **argv) 
{ 
    char *cmd,*splitcmd; 
    int i,j,nargc=0,characters; 
    char **cmdArray; 
    size_t bufsize = 1024; 
    int *pipefd; 
    int pipeArrCount; 
    pid_t pid,wpid; 
    int status = 0; 

    int savestdoutfd = dup(fileno(stdout)); 
    int savestdinfd = dup(fileno(stdin)); 

    cmd = (char *)malloc(bufsize * sizeof(char)); 
    characters = getline(&cmd,&bufsize,stdin); 
// printf("%s%d",cmd,characters); 
    if(cmd[characters-1]=='\n') 
    { 
//  printf("in c"); 
     cmd[characters-1]='\0'; 
     characters--; 
    } 

    cmdArray = (char**)malloc(sizeof(char *) * 100); 
    splitcmd=strtok(cmd,"|"); 
// printf("%s\n",cmd); 
    while((splitcmd)) 
    { 
     cmdArray[nargc] = splitcmd; 
     if(cmdArray[nargc][(strlen(cmdArray[nargc]))-1]==' ') 
      cmdArray[nargc][(strlen(cmdArray[nargc]))-1]='\0'; 
     printf("%d %s",nargc,cmdArray[nargc]); 
     nargc++; 
     splitcmd = strtok(NULL,"|"); 
    } 

    pipefd=(int*)malloc(2*nargc*sizeof(int)); 
    printf("%d\n",nargc); 
    pipeArrCount=2*(nargc-1); 
    printf("%d\n",pipeArrCount); 
    //exit(0); 
    for(i=0;i<pipeArrCount;i) 
    { 
     printf("making pipe for process %d\n",i); 
     pipe(pipefd+i); 
     i=i+2; 
    } 


    //exit(0); 
    for(i=0;i<nargc;i) 
    { 
     printf("parent count %d\n",i); 
     if(i==0) 
     { 
      printf("Creating child %d\n",i); 
      // As it is first process we need to make write end of the pipe as stdout. 
      if ((pid=fork()) == 0) 
      { 
       printf("Creating first child %d for command %s\n",i,cmdArray[i]); 
       printf("EXECUTING FIRST PROCESS\n"); 
       printf("Writing in pipe[%d]\n",2*i+1); 

       //close(pipefd[0]); 

       dup2(pipefd[2*i+1],fileno(stdout)); 
       //closing all other pipes 
       for(j=0;j<(2*nargc);j++) 
       { 
        //if(j!=2*i+1) 
         close(pipefd[j]); 
       } 
       system(cmdArray[i]); 
       //dup2(savestdoutfd,fileno(stdout)); 
       printf("Stdout is again restored\n"); 
       //printf("pipe [%d] contains %d ",2*i+1,pipefd[2*i+1]); 
       exit(0); 
      } 

     } 
     else if(i!=nargc-1) 
     { 
      if (fork() == 0) 
      { 
       printf("EXECUTING MIDDLE PROCESS\n"); 
       printf("Command to execute %s \n",cmdArray[i]); 
       printf("Reading from pipe[%d]\n",(2*(i-1))); 
       printf("writing on pipe[%d]\n",(2*i)+1); 
       dup2(pipefd[(2*(i-1))], 0); //Read end of the previous process pipe as stdin 
       dup2(pipefd[(2*i)+1], 1); //Write end of the pipe of current process as stdout 
       //closing all other pipes 
       for(j=0;j<(2*nargc);j++) 
       { 
        //if((j!=(2*(i-1))) && (j!=(2*i)+1)) 
         close(pipefd[j]); 
       } 
       system(cmdArray[i]); 
       exit(0); 
      } 
     } 
     else 
     { 
      if (fork() == 0) 
      { 
       printf("Creating last child %d for command %s\n",i,cmdArray[i]); 
       printf("Reading from pipe[%d]\n",(2*(i-1))); 

       //close(pipefd[1]); 

       dup2(pipefd[(2*(i-1))],fileno(stdin)); //Read from the end of the previous process pipe as stdin 
       //printf("EXECUTING LAST PROCESS\n"); 
       //closing all other pipes 
       for(i=0;j<(2*nargc);j++) 
       { 
        //if(j!=(2*(i-1))) 
         close(pipefd[j]); 
       } 
       dup2(savestdoutfd,fileno(stdout)); 
       close(savestdoutfd); 
       system(cmdArray[i]); 
       dup2(savestdinfd,fileno(stdin)); 
       close(savestdinfd); 
       exit(0); 
      } 
     } 
     i=i+1; 
     sleep(1); 
    } 
    while ((wpid = wait(&status)) > 0); 
} 

沒有得到第二個命令 的任何輸出現在我試圖執行此'A | B'類型的命令 命令和管道之間的空間是必要的,如果你執行代碼

+0

你能更具體嗎?預計什麼?出了什麼問題? –

+0

我想用c實現unix pipe('|')。 –

+0

我想實現unix pipe('|')使用c.for這個我正在使用pipe()函數進行不同commands.so之間的通信。首先,我嘗試掃描命令並查看需要多少個管道我多次調用管道函數。現在我舉例說明了命令'cat out。c |排序'這個程序做的是獲得一個管道和父進程分別爲兩個命令分出兩個進程第一個命令是使用系統調用執行的,但是這個命令的輸出應該在p [1]的管道的寫入結束處,然後關閉所有pipes.once這樣做....... –

回答

0

你不是一個正確的解決方案。但首先一些通用的言論:

  • 您的代碼不顯示任何包括:請添加它們
  • 你是從鑄造malloc的返回值。這將是用C++必要,但不是在C:你應該寫cmd = malloc(bufsize * sizeof(char));
  • 你可以寫你的循環for(i=0;i<pipeArrCount;i+=2)去除i=i+2,因爲它是在C更常見的用法,或者至少for(i=0;i<pipeArrCount;)避免警告。

現在你的問題的真正原因。您爲管道分配一個大小爲2*nargc的數組,但僅初始化2*(nargc-1)。最後2個是沒有初始化的,應該是無害的,,但是你關閉了整個數組for(j=0;j<(2*nargc);j++)。在我的測試中,它們在0(可能是因爲調試模式),所以你關閉了你的孩子的stdin,只需使用:

for(j=0;j<pipeArrCount;j++) 
{ 
     close(pipefd[j]); 
} 

這還不是全部。你ALSE在最後一個命令一個錯字,你寫for(i=0;j<(2*nargc);j++)i代替j的,它沒有關閉任何這使得代碼只有2命令作爲由Kulwant辛格指出

而且你還必須關閉父進程中的管道,程序結束時應該是:

//closing all pipes 
    for (j=0; j<pipeArrCount; j++) { 
     close(pipefd[j]); 
    } 
    while ((wpid = wait(&status)) > 0); 
} 
+0

感謝您指出錯誤並給出解決方案。 現在有效。 –

0

我執行你的代碼。它適用於單管如:

ls | grep "a" and ls | wc. 

它不適用於雙管如:ls | grep "a" | wc。 錯誤是錯誤的文件描述符

我沒有調試這個錯誤,似乎有一些文件描述符在「else if」子句中處理不當。任何方式你的問題是它不適用於像A | B單管道。但它是。

希望這會有所幫助。