天天看點

詳解linux程序間通信-管道 popen函數 dup2函數

  前言:程序之間交換資訊的唯一方法是經由f o r k或e x e c傳送打開檔案,或通過檔案系統。本章将說明程序之間互相通信的其他技術—I P C(InterProcess Communication)。今天将介紹半雙工的管道。

  一、匿名管道

  1、匿名管道介紹:

   管道有兩種限制;

  (1) 它們是半雙工的。資料隻能在一個方向上流動。

  (2)它們隻能在具有公共祖先的程序之間使用。通常,一個管道由一個程序建立,然後該程序調用f o r k,此後父、子程序之間就可應用該管道。 

  管道是由調用p i p e函數而建立的:

  #include <unistd.h>

  int pipe(intf i l e d e s [ 2 ]) ;

  傳回:若成功則為0,若出錯則為 - 1

  經由參數f i l e d e s傳回兩個檔案描述符: f i l e d e s [ 0 ]為讀而打開, f i l e d e s [ 1 ]為寫而打開。 f i l e d e s [ 1 ]

的輸出是f i l e d e s [ 0 ]的輸入。

  程式1- 1建立了一個從父程序到子程序的管道,并且父程序經由該管道向子程序傳送資料。

#include "my.h"

int main()
{
    int pfd[2],ret;
    ret = pipe(pfd);//建立管道
    if(ret<0)
    {   
        perror("pipe error!");
        exit(-1);
    }   
    pid_t pid = fork();
    if(pid<0)
    {   
        perror("fork error!");
        exit(-1);
    }   
    else if(pid>0)//父程序
    {   
        close(pfd[0]);
        int num;
        puts("please input your num:");
        scanf("%d",&num);
        write(pfd[1],&num,sizeof(num));
        //wait(NULL);
    }   
    else //子程序
    {   
        close(pfd[1]);
        int num;
        read(pfd[0],&num,sizeof(num));
        printf("num:%d\n",num);
    }
    return 0;
}      

  注:頭檔案my.h見這篇部落格:http://www.cnblogs.com/liudw-0215/p/8946879.html 

  運作示例,如下圖:

  

詳解linux程式間通信-管道 popen函數 dup2函數

  接下來介紹幾個跟管道有關的函數。

  2、dup和d u p 2函數  

  下面兩個函數都可用來複制一個現存的檔案描述符:

  int dup(intf i l e d es) ;

  int dup2(int f i l e d e s, int f i l e d e s 2) ;

  兩函數的傳回:若成功為新的檔案描述符,若出錯為- 1

  由d u p傳回的新檔案描述符一定是目前可用檔案描述符中的最小數值。用 d u p 2則可以用f i l e d e s 2

  參數指定新描述符的數值。如果 f i l e d e s 2已經打開,則先将其關閉。如若f i l e d e s等于f i l e d e s 2,則

  d u p 2傳回f i l e d e s 2,而不關閉它。

  優化程式1-1,程式1-2如下:

#include "my.h"

int main()
{
    int pfd[2],ret;
    ret = pipe(pfd);
    if(ret<0)
    {   
        perror("pipe error!");
        exit(-1);
    }   
    pid_t pid = fork();
    if(pid<0)
    {   
        perror("fork error!");
        exit(-1);
    }   
    else if(pid>0)
    {   
        close(pfd[0]);
        int num;
        puts("please input your num:");
        scanf("%d",&num);
        write(pfd[1],&num,sizeof(num));
        wait(NULL);
    }   
    else
    {   
        close(pfd[1]);
        dup2(pfd[0],STDIN_FILENO);//pfd[0]複制到标準輸入
        int num;
        read(STDIN_FILENO,&num,sizeof(num));
        printf("num:%d\n",num);
    }
    return 0;
}      
3、popen和p c l o s e函數  

 因為常見的操作是建立一個連接配接到另一個程序的管道,然後讀其輸出或向其發送輸入,所      

以标準I / O庫為實作這些操作提供了兩個函數 p o p e n和p c l o s e。這兩個函數實作的操作是:建立

一個管道, f o r k一個子程序,關閉管道的不使用端, e x e c一個s h e l l以執行指令,等待指令終止。

  #include <stdio.h>

  FILE *popen(const char * c m d s t r i n g, const char * t y p e) ;

  傳回:若成功則為檔案指針,若出錯則為 N U L L

  int pclose(FILE * f p) ;

  傳回: c m d s t r i n g的終止狀态,若出錯則為 - 1

  函數popen 先執行f o r k,然後調用e x e c以執行c m d s t r i n g,并且傳回一個标準 I / O檔案指針。

  如果t y p e是"r",則檔案指針連接配接到c m d s t r i n g的标準輸出。

  如果t y p e 是"w",則檔案指針連接配接到c m d s t r i n g 的标準輸入。

  程式1-3将用popen函數實作下圖功能:

詳解linux程式間通信-管道 popen函數 dup2函數
#include "my.h"

int main()
{
    int c;
    while((c = getchar()) != EOF)
    {   
        if(isupper(c))  //是否有大寫
            c = tolower(c);  //轉為小寫
        if(putchar(c) == EOF)
            puts("put error!");
        if(c == '\n')
            fflush(stdout);  //重新整理标準輸出
    }   
    exit(0);
}

---isupper.c---      
#include "my.h"
#define MAXLINE 4096

int main()
{
    char line[MAXLINE];
    FILE *fpin;

    if((fpin = popen("./upper","r")) == NULL)
        perror("popen error!");

    for(;;){
        fputs("prompt > ",stdout);
        fflush(stdout);
        if(fgets(line,MAXLINE,fpin) == NULL)
            break;
        if(fputs(line,stdout) == EOF)
            perror("puts error!");    
    }   
    if(pclose(fpin) == -1) 
        perror("pclose error!");

    putchar('\n');
    return 0;

}

---popen.c---      

  運作示範如下圖:

詳解linux程式間通信-管道 popen函數 dup2函數

 二、有名管道(命名管道)

  1、簡介

  命名管道有時被稱為FIFO。管道隻能由相關程序使用,它們共同的祖先程序建立了管道。

但是,通過F I F O,不相關的程序也能交換資料。

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char * p a t h n a m e, mode_tm o d e) ;

傳回:若成功則為0,若出錯則為 - 1

m k f i f o函數中m o de參數的規格說明與o p e n函數中的m o d e相同。

一旦已經用 m k f i f o建立了一個 F I F O,就可用 o p e n打開它。确實,一般的檔案 I / O函數

(c l o s e、 r e a d、 w r i t e、 u n l i n k等)都可用于F I F O。

  程式2-1示範有名管道通信,一個寫端、一個讀端:

#include "my.h"

typedef struct{
    char name[16];
    int age;
    double height;
}Person;

int main()
{
    mkfifo("pipe",0644);//建立管道 名字為pipe
    int fd = open("pipe",O_WRONLY);
    if(fd < 0)
    {   
        perror("open error!");
        exit(-1);    
    }   
    
    Person p;
    puts("please input your name,age,height:");
    scanf("%s%d%lf",p.name,&p.age,&p.height);
    write(fd,&p,sizeof(p));
    close(fd);

    return 0;
}
---fwrite.c---      
#include "my.h"

typedef struct{
    char name[16];
    int age;
    double height;
}Person;

int main()
{
    int fd = open("pipe",O_RDONLY);
    if(fd < 0)
    {   
        perror("open error!");
        exit(-1);
    }   

    Person p;
    read(fd,&p,sizeof(p));
    printf("name:%-5sage:%-5dheight:%-5lf\n ",p.name,p.age,p.height);
    close(fd);
   unlink("pipe");//删除管道檔案

    return 0;

}
--- fread.c ---      

  運作示範:先編譯fwrite.c生成w可執行使用者,./w執行,再編譯fread.c然後執行,寫端輸入資料,讀端輸出資料:

詳解linux程式間通信-管道 popen函數 dup2函數
詳解linux程式間通信-管道 popen函數 dup2函數

總結:主要介紹了程序間通信的管道,主要分為匿名管道和有名管道,還介紹了popen等函數

作者:

柳德維

出處:

https://www.cnblogs.com/liudw-0215/

-------------------------------------------

個性簽名:獨學而無友,則孤陋而寡聞。做一個靈魂有趣的人!

如果覺得這篇文章對你有小小的幫助的話,記得在右下角點個“推薦”哦,部落客在此感謝!

萬水千山總是情,打賞一分行不行,是以如果你心情還比較高興,也是可以掃碼打賞部落客,哈哈哈(っ•̀ω•́)っ⁾⁾!

繼續閱讀