詳解linux進程間通訊-管道 popen函數 dup2函數

  前言:進程之間交換信息的惟一方法是經由f o r ke x e c傳送打開文件,或經過文件系統。本章將說明進程之間相互通訊的其餘技術—I P CInterProcess Communication)。今天將介紹半雙工的管道。html

  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
spa

  經由參數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建立了一個從父進程到子進程的管道,而且父進程經由該管道向子進程傳送數據。code

#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 htm

  運行示例,以下圖:blog

  

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

  二、dupd u p 2函數  ip

  下面兩個函數均可用來複制一個現存的文件描述符:

  #include <unistd.h>

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

  

三、popenp c l o s e函數  

 由於常見的操做是建立一個鏈接到另外一個進程的管道,而後讀其輸出或向其發送輸入,所

以標準I / O庫爲實現這些操做提供了兩個函數 p o p e np 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函數實現下圖功能:

  

  

#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---

  運行演示以下圖:

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

  一、簡介

  命名管道有時被稱爲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 er e a dw r i t eu 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而後執行,寫端輸入數據,讀端輸出數據:

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

相關文章
相關標籤/搜索