亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

進程間通信之popen和pclose函數

2024-06-28 13:27:55
字體:
來源:轉載
供稿:網友
進程間通信之popen和pclose函數

常見的操作是創建一個管道連接到另一個進程,然后讀其輸出或向其輸入端發送數據,為此,標準I/O庫提供了兩個函數popen和pclose。這兩個函數實現的操作是:創建一個管道,調用fork產生一個子進程,關閉管道的不使用端,執行一個shell以運行命令,然后等待命令終止

#include <stdio.h>FILE *popen(const char *cmdstring, const char *type);返回值:若成功則返回文件指針,若出錯則返回NULLint pclose(FILE *fp);返回值:cmdstring的終止狀態,若出錯則返回-1

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

未命名

fp相當于管道的fd[0], stdout相當于管道的fd[1].

圖15-5 執行fp = popen(cmdstring, “r”)函數的結果

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

未命名

fp相當于管道的fd[1], stdin相當于管道的fd[0].

圖15-6 執行fp = popen(cmdstring, “w”)函數的結果

pclose函數關閉標準I/O流,等待命令執行結束,然后返回shell的終止狀態。(我們曾在http://www.CUOXin.com/nufangrensheng/p/3510101.html對終止狀態進行過說明,system函數(http://www.CUOXin.com/nufangrensheng/p/3512291.html)也返回終止狀態。)如果shell不能被執行,則pclose返回的終止狀態與shell已執行exit(127)一樣。

cmdstring由Bourne shell以下列方式執行:

sh -c cmdstring

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

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

實例

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

#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已經定義,且其值非空,則使用其值,否則使用字符串more。

實例:popen和pclose函數

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

程序清單15-5 popen和pclose函數

#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()函數見http://www.CUOXin.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 */}

這里有許多需要考慮的細節:首先,每次調用popen時,應當記住所創建的子進程的進程ID,以及其文件描述符或FILE指針。我們選擇在數組childpid中保存子進程ID,并用文件描述符作為其下標。于是,當以FILE指針作為參數調用pclose時,我們調用標準I/O函數fileno得到文件描述符,然后取得子進程ID,并用其作為參數調用waitpid。因為一個進程可能調用popen多次,所以在動態分配childpid數組時(第一次調用popen時),其數組長度應當是最大文件描述符數,于是該數組中可以存放與最大文件描述符數相同的子進程。

POSIX.1要求子進程 關閉在之前調用popen時打開且當前仍舊打開的所有I/O流。為此,在子進程中從頭逐個檢查childpid數組的各元素,關閉仍舊打開的任何描述符。

若pclose的調用者已經為信號SIGCHLD設置了一個信號處理程序,則pclose中的waitpid調用將返回一個EINTR。因為允許調用者捕捉此信號(或者任何其他可能中斷waitpid調用的信號),所以當waitpid被一個捕捉到的信號中斷時,我們只是再次調用waitpid。

注意,如果應用程序調用waitpid,并且獲得popen所創建的子進程的終止狀態,則在應用程序調用pclose時,其中將調用waitpid,它發現子進程已不再存在,此時返回-1,errno被設置為ECHILD。

注意,popen絕不應由設置用戶ID或設置用戶組ID程序調用。當它執行命令時,popen等同于:

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

它在從調用者繼承的環境中執行shell,并由shell解釋執行command。一個心懷不軌的用戶可以操縱這種環境,使得shell能以設置ID文件模式所授予的提升了的權限以及非預期的方式執行命令。

popen特別適用于構造簡單的過濾器程序,它變換運行命令的輸入或輸出。當命令希望構造它自己的管道線時,就是這種情形。

實例

考慮一個應用程序,它向標準輸出寫一個提示,然后從標準輸入讀1行。使用popen,可以在應用程序和輸入之間插入一個程序以便對輸入進行變換處理。圖15-7顯示了為此做的進程安排。

未命名

圖15-7 用popen對輸入進行變換處理

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

程序清單15-6是一個簡單的過濾程序,它只是將標準輸入復制到標準輸出,在復制時,將所有大寫字符變換為小寫字符。在寫了一行以后,對標準輸出進行了沖洗(用fflush),其理由可參考進程間通信之協同進程。

程序清單15-6 將大寫字符轉換成小寫字符的過濾程序

#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);}

對該過濾程序進行編譯,其可執行目標代碼放在文件myuclc中(也就是編譯后的可執行文件名為myuclc),然后在程序清單15-7中用popen調用它們。

程序清單15-7 調用大寫/小寫過濾程序以讀取命令

#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);}

因為標準輸出通常是行緩沖的,而提示符并不包括換行符,所以在寫了提示之后,需要調用fflush。

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产女人aaa毛片在线| 亚洲成人性视频| 91麻豆国产精品| 亚洲电影免费观看| 黑人精品xxx一区| 精品国内产的精品视频在线观看| 日韩美女免费视频| 亚洲女人被黑人巨大进入al| 97视频在线观看免费| 在线播放亚洲激情| 中文字幕精品视频| 欧美老女人www| 日韩欧美在线免费| 国产噜噜噜噜噜久久久久久久久| 国产精品视频免费在线| 亚洲精品电影久久久| 91麻豆国产精品| 久久久久久亚洲精品中文字幕| 日韩风俗一区 二区| 九九热精品在线| 国产乱肥老妇国产一区二| 久久久久久久久久久网站| 国产精品69精品一区二区三区| 国产一区二区丝袜高跟鞋图片| 亚洲国产精品99| 欧美日韩第一页| 性欧美暴力猛交69hd| 亚洲自拍偷拍福利| 国产999精品视频| 亚洲女人天堂色在线7777| 欧美性猛交xxxx偷拍洗澡| 国产视频精品一区二区三区| 黄网站色欧美视频| 日韩资源在线观看| 精品视频中文字幕| 狠狠做深爱婷婷久久综合一区| 亚洲午夜久久久久久久| 国产成人精品999| 中文日韩在线观看| 91在线看www| 国产精品亚洲网站| 久久露脸国产精品| 2019亚洲男人天堂| 亚洲欧洲日产国产网站| 久久综合九色九九| 91啪国产在线| 日本精品一区二区三区在线播放视频| 日韩精品极品在线观看| 国产97免费视| 久久久久久久久网站| 国产精品丝袜久久久久久高清| 久久精品国产2020观看福利| 成人在线视频福利| 亚洲视频在线免费观看| 91久久综合亚洲鲁鲁五月天| 亚洲色图欧美制服丝袜另类第一页| 久久影视三级福利片| 伊人久久男人天堂| 亚洲天堂久久av| 欧美大片免费观看在线观看网站推荐| 久久久免费观看视频| 在线观看国产精品91| 国产精品男女猛烈高潮激情| 日韩欧美主播在线| 91欧美激情另类亚洲| 精品国偷自产在线| 中文字幕欧美视频在线| 97欧美精品一区二区三区| 91成品人片a无限观看| 国产精品第一区| 精品中文字幕在线观看| 亚洲午夜女主播在线直播| 欧美高清视频在线观看| 亚洲成avwww人| 91美女福利视频高清| 九色91av视频| 黄色成人av网| 色综合男人天堂| 国产精品国内视频| 91精品在线国产| 国产精品视频区| 国产欧美一区二区白浆黑人| 精品国产成人在线| 日韩美女在线观看一区| 人妖精品videosex性欧美| 欧美亚洲另类视频| 亚洲免费电影一区| 中文字幕精品视频| 久热在线中文字幕色999舞| 国产精品老牛影院在线观看| 欧美性感美女h网站在线观看免费| 在线精品播放av| 久久精品国产亚洲7777| 久久午夜a级毛片| 欧美色欧美亚洲高清在线视频| 亚洲伦理中文字幕| 66m—66摸成人免费视频| 亚洲精品视频免费在线观看| 亚洲第一中文字幕在线观看| 亚洲一区二区三区在线视频| 欧美在线中文字幕| 91性高湖久久久久久久久_久久99| 亚洲福利在线观看| 欧美大秀在线观看| 亚洲国产成人av在线| 日本不卡免费高清视频| 亚洲欧美精品中文字幕在线| 日韩精品免费视频| 亚洲第一视频在线观看| 日韩精品免费在线| 色噜噜久久综合伊人一本| 日本亚洲欧美三级| 日韩成人av在线| 色av吧综合网| 97精品欧美一区二区三区| 91精品国产成人| 欧美精品videos| 欧美性高潮在线| 欧美日韩在线视频一区二区| 免费97视频在线精品国自产拍| 伊人伊成久久人综合网小说| 久久999免费视频| 亚洲精品久久久久久久久久久久久| 97精品在线观看| 国产在线观看一区二区三区| 国产一区二区在线播放| 亚洲精品视频在线播放| 欧美日韩国产色视频| 日韩精品在线观看网站| 日本伊人精品一区二区三区介绍| 欧美日韩国产999| 97欧美精品一区二区三区| 久久天天躁夜夜躁狠狠躁2022| 国产免费一区二区三区香蕉精| 成人久久久久爱| 在线观看国产精品日韩av| xxxx欧美18另类的高清| 国产精品网站大全| 色老头一区二区三区在线观看| 亚洲日本成人网| 欧美午夜精品久久久久久人妖| 日韩一区二区福利| 国产97在线|日韩| 亚洲欧美在线免费观看| 色综合天天综合网国产成人网| 国产情人节一区| 日韩免费中文字幕| 91亚洲一区精品| 久久国产精品影片| 亚洲香蕉在线观看| 国产在线视频2019最新视频| 亚洲在线观看视频网站| 日本亚洲精品在线观看| 91久久久亚洲精品| 91九色国产社区在线观看| 亚洲一区亚洲二区亚洲三区| 亚洲日本aⅴ片在线观看香蕉| 疯狂做受xxxx欧美肥白少妇| 国产一区视频在线| 国产精品av免费在线观看| 日韩一级裸体免费视频| 欧美激情免费在线| 国外成人在线播放| 国产精品一二三视频|