Linux系統程式設計—有名管道
▋1. 管道的概念
管道,又名「無名管理」,或「匿名管道」,管道是一種非常基本,也是使用非常頻繁的IPC方式。
1.1 管道本質
- 管道的本質也是一種檔案,不過是偽檔案,實際上是一塊核心緩衝區,大小4K;
- 管道建立以後會產生兩個檔案描述符,一個是讀端,另一個是寫端;
- 管道里的資料只能從寫端被寫入,從讀端被讀出;
1.2 管道原理
管道是核心的一塊緩衝區,更具體一些,是一個環形佇列。資料從佇列的一端寫入資料,另一端讀出,如下圖示:

img
1.3 管道的優點
簡單
1.4 管道的缺點
- 只能單向通訊,如果需要雙向通訊則需要建立兩個管道;
- 只能應用於具有血緣關係的程序,如父子程序;
- 緩衝區大小受限,通常為1頁,即4k;
▋2. 管道的建立
管道建立三步曲:
a. 父程序呼叫pipe函式建立管道;
b. 父程序呼叫fork函式建立子程序;
c. 父程序關閉fd[0],子程序關閉fd[1];
具體如下圖所示:

img
▋3. 管道的讀寫行為
a. 管道的緩衝區大小固定為4k,所以如果管道內資料已經寫滿,則無法再寫入資料,程序的write呼叫將阻塞,直到有足夠的空間再寫入資料;
b. 管道的讀動作比寫動作要快,資料一旦被讀走了,管道將釋放相應的空間,以便後續資料的寫入。當所有的資料都讀完之後,程序的read()呼叫將阻塞,直到有資料再次寫入。
▋4. 例程
父子間通訊:
1#include <stdio.h> 2#include <sys/types.h> 3#include <unistd.h> 4#include <string.h> 5 6int main() 7{ 8int fd[2]; 9pid_t pid; 10char buf[1024]; 11char *data = "hello world!"; 12 13/* 建立管道 */ 14if (pipe(fd) == -1) { 15printf("ERROR: pipe create failed!\n"); 16return -1; 17} 18 19pid = fork(); 20if (pid == 0) { 21/* 子程序 */ 22close(fd[1]);// 子程序讀取資料,關閉寫端 23read(fd[0], buf, sizeof(buf));// 從管道讀資料 24printf("child process read: %s\n", buf); 25close(fd[0]); 26} else if (pid > 0) { 27/* 父程序 */ 28close(fd[0]);//父程序寫資料,關閉讀端 29write(fd[1], data, strlen(data));// 向管道寫資料 30printf("parent process write: %s\n", data); 31close(fd[1]); 32} 33 34return 0; 35} 複製程式碼
兄弟間通訊:
1#include <stdio.h> 2#include <sys/types.h> 3#include <unistd.h> 4#include <string.h> 5#include <sys/wait.h> 6 7int main () 8{ 9int fd[2]; 10int i = 0; 11pid_t pid; 12char buf[1024]; 13char *data = "hello world!"; 14 15/* 建立管道 */ 16if (pipe(fd) == -1) { 17printf("ERROR: pipe create failed!\n"); 18return -1; 19} 20 21for (i = 0; i < 2; i++) { 22pid = fork(); 23if (pid == -1) { 24printf("ERROR: fork error!\n"); 25return -1; 26} else if (pid == 0) { 27break; 28} 29} 30 31/* 通過i來判斷建立的子程序及父程序 */ 32if (i == 0) { 33/* 第一個子程序,兄程序 */ 34close(fd[0]);// 兄程序向弟程序寫資料,關閉讀端 35write(fd[1], data, strlen(data)); 36printf("elder brother send: %s\n", data); 37close(fd[1]); 38} else if (i == 1) { 39/* 第二個子程序,弟程序 */ 40close(fd[1]); 41read(fd[0], buf, sizeof(buf)); 42printf("younger brother receive: %s\n", buf); 43close(fd[0]); 44} else { 45/* 父程序 */ 46close(fd[0]); 47close(fd[1]); 48for (i = 0; i < 2; i++) { 49wait(NULL); 50} 51} 52 53return 0; 54} 複製程式碼
更多精彩內容,請關注公眾號 良許Linux ,公眾內回覆 1024 可免費獲得5T技術資料,包括: Linux,C/C++,Python,樹莓派,嵌入式,Java,人工智慧 ,等等。公眾號內回覆 進群 ,邀請您進高手如雲技術交流群。
Line"/>