前言:進程之間交換信息的惟一方法是經由f o r k或e x e c傳送打開文件,或經過文件系統。本章將說明進程之間相互通訊的其餘技術—I P C(InterProcess Communication)。今天將介紹半雙工的管道。html
一、匿名管道介紹:函數
管道有兩種限制;
(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
接下來介紹幾個跟管道有關的函數。進程
二、dup和d 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; }
三、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函數實現下圖功能:
#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 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而後執行,寫端輸入數據,讀端輸出數據:
總結:主要介紹了進程間通訊的管道,主要分爲匿名管道和有名管道,還介紹了popen等函數