电竞比分网-中国电竞赛事及体育赛事平台

分享

自己實(shí)現(xiàn)popen函數(shù)

 xsx2008 2014-01-23

自己實(shí)現(xiàn)popen函數(shù)

2545人閱讀 評論(3) 收藏 舉報(bào)

   閑來無事,自己實(shí)現(xiàn)了popen函數(shù)mypopen,后來查看了popen函數(shù)的源碼發(fā)現(xiàn)自己實(shí)現(xiàn)的與其相差無幾,本函數(shù)與linux中的實(shí) 現(xiàn)最大的不同是不需要用專門的pclose()函數(shù)來關(guān)閉文件指針,用普通的fclose()即可,linux實(shí)現(xiàn)的代碼也會(huì)給出在下文,可以對比一下其 中差異。

 

   主要通過pipe管道實(shí)現(xiàn),具體思路如下:

        1、使用pipe()建立管道

        2、使用fork()創(chuàng)建子進(jìn)程

        3、在子進(jìn)程中調(diào)用exec族函數(shù)執(zhí)行命令,通過管道將結(jié)果傳送至父進(jìn)程

        4、在主進(jìn)程中等待子進(jìn)程執(zhí)行,子進(jìn)程執(zhí)行完成后將接收其結(jié)果,返回結(jié)果的文件指針

 

  下面是mypopen源代碼,重點(diǎn)部位已通過注釋進(jìn)行標(biāo)注:

    

  1. FILE *mypopen(char *cmd,char type)  
  2. {  
  3.     int pipefd[2];           //管道描述符  
  4.     int pid_t;               //進(jìn)程描述符  
  5.   
  6.     if(type !='r' && type != 'w')  
  7.     {  
  8.         printf("myopen() flag error/n");  
  9.         return NULL;  
  10.     }  
  11.   
  12.     if(pipe(pipefd)<0)        //建立管道  
  13.     {  
  14.         printf("myopen() pipe create error/n");  
  15.         return NULL;  
  16.     }  
  17.       
  18.     pid_t=fork();             //建立子進(jìn)程  
  19.   
  20.     if(pid_t < 0)   
  21.         return NULL;  
  22.   
  23.     if(0 == pid_t)            //子進(jìn)程中......  
  24.     {  
  25.         if(type == 'r')  
  26.         {  
  27.             close(pipefd[0]);               //此函數(shù)返回文件指針是用于讀,因此,在子進(jìn)程中應(yīng)該將結(jié)果寫入管道,這樣父進(jìn)程返回的文件指針才能讀,所以這里將讀端關(guān)閉  
  28.             dup2(pipefd[1],STDOUT_FILENO);  //exec函數(shù)的執(zhí)行結(jié)果將會(huì)通過標(biāo)準(zhǔn)輸出寫到控制臺上,但這里我們不需要在控制臺輸出,而是需要將結(jié)果返回,因此將標(biāo)準(zhǔn)輸出重定向到管道寫端  
  29.             close(pipefd[1]);         
  30.   
  31.         }  
  32.         else{  
  33.             close(pipefd[1]);  
  34.             dup2(pipefd[0],STDIN_FILENO);  
  35.             close(pipefd[0]);  
  36.         }  
  37.         char *argv[] = {cmd,NULL};    
  38.         if(execvp(cmd,argv)<0)          //用exec族函數(shù)執(zhí)行命令  
  39.             return NULL;      
  40.     }  
  41.       
  42.     wait(0);                                //等待子進(jìn)程返回  
  43.   
  44.     if(type=='r'){  
  45.         close(pipefd[1]);  
  46.         return fdopen(pipefd[0],"r");   //由于程序需要返回的參數(shù)是文件指針,因此需要用fdopen函數(shù)將描述符打開,其返回值為相應(yīng)的文件指針   
  47.     }else{  
  48.         close(pipefd[0]);  
  49.         return fdopen(pipefd[1],"w");  
  50.     }  
  51. }  
 

 

 

   下面是popen()在linux中的實(shí)現(xiàn):

    

  1. /* 
  2.  *  popen.c     Written by W. Richard Stevens 
  3.  */  
  4.   
  5. #include    <sys/wait.h>  
  6. #include    <errno.h>  
  7. #include    <fcntl.h>  
  8. #include    "ourhdr.h"  
  9.   
  10. static pid_t    *childpid = NULL;  
  11.                         /* ptr to array allocated at run-time */  
  12. static int      maxfd;  /* from our open_max(), {Prog openmax} */  
  13.   
  14. #define SHELL   "/bin/sh"  
  15.   
  16. FILE *  
  17. popen(const char *cmdstring, const char *type)  
  18. {  
  19.     int     i, pfd[2];  
  20.     pid_t   pid;  
  21.     FILE    *fp;  
  22.   
  23.             /* only allow "r" or "w" */  
  24.     if ((type[0] != 'r' && type[0] != 'w') || type[1] != 0) {  
  25.         errno = EINVAL;     /* required by POSIX.2 */  
  26.         return(NULL);  
  27.     }  
  28.   
  29.     if (childpid == NULL) {     /* first time through */  
  30.                 /* allocate zeroed out array for child pids */  
  31.         maxfd = open_max();  
  32.         if ( (childpid = calloc(maxfd, sizeof(pid_t))) == NULL)  
  33.             return(NULL);  
  34.     }  
  35.   
  36.     if (pipe(pfd) < 0)  
  37.         return(NULL);   /* errno set by pipe() */  
  38.   
  39.     if ( (pid = fork()) < 0)  
  40.         return(NULL);   /* errno set by fork() */  
  41.     else if (pid == 0) {                            /* child */  
  42.         if (*type == 'r') {  
  43.             close(pfd[0]);  
  44.             if (pfd[1] != STDOUT_FILENO) {  
  45.                 dup2(pfd[1], STDOUT_FILENO);  
  46.                 close(pfd[1]);  
  47.             }  
  48.         } else {  
  49.             close(pfd[1]);  
  50.             if (pfd[0] != STDIN_FILENO) {  
  51.                 dup2(pfd[0], STDIN_FILENO);  
  52.                 close(pfd[0]);  
  53.             }  
  54.         }  
  55.             /* close all descriptors in childpid[] */  
  56.         for (i = 0; i < maxfd; i++)  
  57.             if (childpid[ i ] > 0)  
  58.                 close(i);  
  59.   
  60.         execl(SHELL, "sh""-c", cmdstring, (char *) 0);  
  61.         _exit(127);  
  62.     }  
  63.                                 /* parent */  
  64.     if (*type == 'r') {  
  65.         close(pfd[1]);  
  66.         if ( (fp = fdopen(pfd[0], type)) == NULL)  
  67.             return(NULL);  
  68.     } else {  
  69.         close(pfd[0]);  
  70.         if ( (fp = fdopen(pfd[1], type)) == NULL)  
  71.             return(NULL);  
  72.     }  
  73.     childpid[fileno(fp)] = pid; /* remember child pid for this fd */  
  74.     return(fp);  
  75. }  
  76.   
  77. int  
  78. pclose(FILE *fp)  
  79. {  
  80.   
  81.     int     fd, stat;  
  82.     pid_t   pid;  
  83.   
  84.     if (childpid == NULL)  
  85.         return(-1);     /* popen() has never been called */  
  86.   
  87.     fd = fileno(fp);  
  88.     if ( (pid = childpid[fd]) == 0)  
  89.         return(-1);     /* fp wasn't opened by popen() */  
  90.   
  91.     childpid[fd] = 0;  
  92.     if (fclose(fp) == EOF)  
  93.         return(-1);  
  94.   
  95.     while (waitpid(pid, &stat, 0) < 0)  
  96.         if (errno != EINTR)  
  97.             return(-1); /* error other than EINTR from waitpid() */  
  98.   
  99.     return(stat);   /* return child's termination status */  
  100. }  

 

    參考資料,真誠致謝:

   http://www./forum/showflat.php?Cat=&Board=program&Number=266385 

 

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多