国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
進(jìn)程間通信之popen和pclose函數(shù)

常見的操作是創(chuàng)建一個(gè)管道連接到另一個(gè)進(jìn)程,然后讀其輸出或向其輸入端發(fā)送數(shù)據(jù),為此,標(biāo)準(zhǔn)I/O庫(kù)提供了兩個(gè)函數(shù)popen和pclose。這兩個(gè)函數(shù)實(shí)現(xiàn)的操作是:創(chuàng)建一個(gè)管道,調(diào)用fork產(chǎn)生一個(gè)子進(jìn)程,關(guān)閉管道的不使用端,執(zhí)行一個(gè)shell以運(yùn)行命令,然后等待命令終止。

#include <stdio.h>FILE *popen(const char *cmdstring, const char *type);返回值:若成功則返回文件指針,若出錯(cuò)則返回NULLint pclose(FILE *fp);返回值:cmdstring的終止?fàn)顟B(tài),若出錯(cuò)則返回-1

函數(shù)popen先執(zhí)行fork,然后調(diào)用exec以執(zhí)行cmdstring,并且返回一個(gè)標(biāo)準(zhǔn)I/O文件指針。如果type是“r”,則文件指針連接到cmdstring的標(biāo)準(zhǔn)輸出(見圖15-5)。

    fp相當(dāng)于管道的fd[0], stdout相當(dāng)于管道的fd[1].

    圖15-5 執(zhí)行fp = popen(cmdstring, “r”)函數(shù)的結(jié)果

如果type是“w”,則文件指針連接到cmdstring的標(biāo)準(zhǔn)輸入(見圖15-6)。

      fp相當(dāng)于管道的fd[1], stdin相當(dāng)于管道的fd[0].

      圖15-6 執(zhí)行fp = popen(cmdstring, “w”)函數(shù)的結(jié)果

pclose函數(shù)關(guān)閉標(biāo)準(zhǔn)I/O流,等待命令執(zhí)行結(jié)束,然后返回shell的終止?fàn)顟B(tài)。(我們?cè)?a title="http://www.cnblogs.com/nufangrensheng/p/3510101.html" >http://www.cnblogs.com/nufangrensheng/p/3510101.html對(duì)終止?fàn)顟B(tài)進(jìn)行過(guò)說(shuō)明,system函數(shù)(http://www.cnblogs.com/nufangrensheng/p/3512291.html)也返回終止?fàn)顟B(tài)。)如果shell不能被執(zhí)行,則pclose返回的終止?fàn)顟B(tài)與shell已執(zhí)行exit(127)一樣。

cmdstring由Bourne shell以下列方式執(zhí)行:

sh -c cmdstring

這表示shell將擴(kuò)展cmdstring中的任何特殊字符。 例如,可以使用:

fp = popen("ls *.c", "r");或者fp = popen("cmd 2>&1", "r");

實(shí)例

  程序清單15-4 用popen向分頁(yè)程序傳送文件

#include "apue.h"#include <sys/wait.h>#define PAGER    "${PAGER:-more}"    /* environment variable, or default */intmain(int argc, char *argv[]){    char    line[MAXLINE];    FILE    *fpin, *fpout;    if(argc != 2)        err_quit("usage: a.out <pathname>");    if((fpin = fopen(argv[1], "r")) == NULL)        err_sys("can't open %s", argv[1]);    if((fpout = popen(PAGER, "w")) == NULL)        err_sys("popen error");    /* copy argv[1] to pager */    while(fgets(line, MAXLINE, fpin) != NULL)    {        if(fputs(line, fpout) == EOF)            err_sys("fputs error to pipe");    }    if(ferror(fpin))        err_sys("fgets error");    if(pclose(fpout) == -1)        err_sys("pclose error");    exit(0);}

使用popen減少了需要編寫的代碼量。

shell命令${PAGER:-more}的意思是:如果shell變量PAGER已經(jīng)定義,且其值非空,則使用其值,否則使用字符串more。

實(shí)例:popen和pclose函數(shù)

程序清單15-5是我們編寫的popen和pclose版本。

程序清單15-5 popen和pclose函數(shù)

#include "apue.h"#include <errno.h>#include <fcntl.h>#include <sys/wait.h>/** Pointer to array allocated at run-time.*/static pid_t    *childpid = NULL;/** From our open_max(), open_max()函數(shù)見http://www.cnblogs.com/nufangrensheng/p/3496323.html中的程序清單2-4。*/static int maxfd;FILE *popen(const char *cmdstring, const char *type){    int      i;    int      pfd[2];    pid_t    pid;    FILE    *fp;        /* only allow "r" or "w" */    if((type[0] != 'r' &&  type[0] != 'w') || type[1] != 0)    {        errno = EINVAL;    /* required by POSIX */        return(NULL);    }        if(childpid == NULL)    /* first time through */    {        /* allocate zerod out array for child pids */        maxfd = open_max();        if((childpid = calloc(maxfd, sizeof(pid_t))) == NULL)            return(NULL);    }        if(pipe(pfd) < 0)        return(NULL);    /* errno set by pipe() */    if((pid = fork()) < 0)    {        return(NULL);    /* error set by fork() */    }    else if(pid == 0)    {        if(*type == 'r')        {            close(pfd[0]);            if(pfd[1] != STDOUT_FILENO)            {                dup2(pfd[1], STDOUT_FILENO);                close(pfd[1]);                }        }        else        {            close(pfd[1]);            if(pfd[0] != STDIN_FILENO)            {                dup2(pfd[0], STDIN_FILENO);                close(pfd[0]);            }        }                /* close all descriptors in childpid[] */        for(i=0; i < maxfd; i++)            if(childpid[i] > 0)                close(i);        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);        _exit(127);    }    /* parent continues... */    if(*type == 'r')    {        close(pfd[1]);        if((fp = fdopen(pfd[0], type)) == NULL)            return(NULL);    }    else    {        close(pfd[0]);        if((fp = fdopen(pfd[1], type)) == NULL)            return(NULL);    }        childpid[fileno(fp)] = pid;    /* remeber child pid for this fd */    return(fp);}intpclose(FILE *fp){    int      fd, stat;    pid_t    pid;    if(childpid == NULL)    {        errno = EINVAL;        return(-1);    /* popen() has never been called */    }        fd = fileno(fp);    if((pid = childpid[fd]) = 0)    {        errno = EINVAL;        return(-1);    /*  fp wasn't opened by popen() */    }    childpid[fd] = 0;    if(fclose(fp) == EOF)        return(-1);    while(waitpid(pid, &stat, 0) < 0)        if(errno != EINTR)            return(-1);    /* error other than EINTR from waitpid() */    return(stat);        /* return child's termination status */}

這里有許多需要考慮的細(xì)節(jié):首先,每次調(diào)用popen時(shí),應(yīng)當(dāng)記住所創(chuàng)建的子進(jìn)程的進(jìn)程ID,以及其文件描述符或FILE指針。我們選擇在數(shù)組childpid中保存子進(jìn)程ID,并用文件描述符作為其下標(biāo)。于是,當(dāng)以FILE指針作為參數(shù)調(diào)用pclose時(shí),我們調(diào)用標(biāo)準(zhǔn)I/O函數(shù)fileno得到文件描述符,然后取得子進(jìn)程ID,并用其作為參數(shù)調(diào)用waitpid。因?yàn)橐粋€(gè)進(jìn)程可能調(diào)用popen多次,所以在動(dòng)態(tài)分配childpid數(shù)組時(shí)(第一次調(diào)用popen時(shí)),其數(shù)組長(zhǎng)度應(yīng)當(dāng)是最大文件描述符數(shù),于是該數(shù)組中可以存放與最大文件描述符數(shù)相同的子進(jìn)程。

POSIX.1要求子進(jìn)程 關(guān)閉在之前調(diào)用popen時(shí)打開且當(dāng)前仍舊打開的所有I/O流。為此,在子進(jìn)程中從頭逐個(gè)檢查childpid數(shù)組的各元素,關(guān)閉仍舊打開的任何描述符。

若pclose的調(diào)用者已經(jīng)為信號(hào)SIGCHLD設(shè)置了一個(gè)信號(hào)處理程序,則pclose中的waitpid調(diào)用將返回一個(gè)EINTR。因?yàn)樵试S調(diào)用者捕捉此信號(hào)(或者任何其他可能中斷waitpid調(diào)用的信號(hào)),所以當(dāng)waitpid被一個(gè)捕捉到的信號(hào)中斷時(shí),我們只是再次調(diào)用waitpid。

注意,如果應(yīng)用程序調(diào)用waitpid,并且獲得popen所創(chuàng)建的子進(jìn)程的終止?fàn)顟B(tài),則在應(yīng)用程序調(diào)用pclose時(shí),其中將調(diào)用waitpid,它發(fā)現(xiàn)子進(jìn)程已不再存在,此時(shí)返回-1,errno被設(shè)置為ECHILD。

注意,popen絕不應(yīng)由設(shè)置用戶ID或設(shè)置用戶組ID程序調(diào)用。當(dāng)它執(zhí)行命令時(shí),popen等同于:

execl("/bin/sh", "sh", "-c", command, NULL);

它在從調(diào)用者繼承的環(huán)境中執(zhí)行shell,并由shell解釋執(zhí)行command。一個(gè)心懷不軌的用戶可以操縱這種環(huán)境,使得shell能以設(shè)置ID文件模式所授予的提升了的權(quán)限以及非預(yù)期的方式執(zhí)行命令。

popen特別適用于構(gòu)造簡(jiǎn)單的過(guò)濾器程序,它變換運(yùn)行命令的輸入或輸出。當(dāng)命令希望構(gòu)造它自己的管道線時(shí),就是這種情形。

實(shí)例

考慮一個(gè)應(yīng)用程序,它向標(biāo)準(zhǔn)輸出寫一個(gè)提示,然后從標(biāo)準(zhǔn)輸入讀1行。使用popen,可以在應(yīng)用程序和輸入之間插入一個(gè)程序以便對(duì)輸入進(jìn)行變換處理。圖15-7顯示了為此做的進(jìn)程安排。

                            圖15-7 用popen對(duì)輸入進(jìn)行變換處理

對(duì)輸入進(jìn)行的變化可能是路徑名擴(kuò)充,或者是提供一種歷史機(jī)制(記住以前輸入的命令)。

程序清單15-6是一個(gè)簡(jiǎn)單的過(guò)濾程序,它只是將標(biāo)準(zhǔn)輸入復(fù)制到標(biāo)準(zhǔn)輸出,在復(fù)制時(shí),將所有大寫字符變換為小寫字符。在寫了一行以后,對(duì)標(biāo)準(zhǔn)輸出進(jìn)行了沖洗(用fflush),其理由可參考進(jìn)程間通信之協(xié)同進(jìn)程。

程序清單15-6 將大寫字符轉(zhuǎn)換成小寫字符的過(guò)濾程序

#include "apue.h"#include <ctype.h>intmain(void){    int c;        while((c = getchar()) != EOF)    {        if(isupper(c))            c = tolower(c);        if(putchar(c) == EOF)            err_sys("output error");        if(c == '\n')            fflush(stdout);    }    exit(0);}

對(duì)該過(guò)濾程序進(jìn)行編譯,其可執(zhí)行目標(biāo)代碼放在文件myuclc中(也就是編譯后的可執(zhí)行文件名為myuclc),然后在程序清單15-7中用popen調(diào)用它們。

程序清單15-7 調(diào)用大寫/小寫過(guò)濾程序以讀取命令

#include "apue.h"#include <sys/wait.h>intmain(void){    char    line[MAXLINE];    FILE    *fpin;    if((fpin = popen("/home/zhu/apue/myuclc", "r")) == NULL)        err_sys("popen error");    for(;;)    {        fputs("prompt> ", stdout);        fflush(stdout);        if(fgets(line, MAXLINE, fpin) == NULL)    /* read from pipe */            break;        if(fputs(line, stdout) == EOF)            err_sys("fputs error to pipe");    }    if(pclose(fpin) == -1)        err_sys("pclose error");    putchar('\n');    exit(0);}

因?yàn)闃?biāo)準(zhǔn)輸出通常是行緩沖的,而提示符并不包括換行符,所以在寫了提示之后,需要調(diào)用fflush。

本篇博文內(nèi)容摘自《UNIX環(huán)境高級(jí)編程》(第二版),僅作個(gè)人學(xué)習(xí)記錄所用。關(guān)于本書可參考:http://www.apuebook.com/。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
自己實(shí)現(xiàn)popen函數(shù)
linux一切皆文件|細(xì)節(jié)知多少
popen的使用
進(jìn)程間通信--管道
popen的用法及與system調(diào)用的區(qū)別
對(duì)于linux下system()函數(shù)的深度理解(整理)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服