Linux系統編程—有名管道

▋**1. 管道的概念**

管道,又名「無名管理」,或「匿名管道」,管道是一種非常基本,也是使用非常頻繁的IPC方式。

1.1 管道本質

管道的本質也是一種文件,不過是偽文件,實際上是一塊內核緩衝區,大小4K;管道創建以後會產生兩個文件描述符,一個是讀端,另一個是寫端;管道里的數據只能從寫端被寫入,從讀端被讀出;

1.2 管道原理

管道是內核的一塊緩衝區,更具體一些,是一個環形隊列。數據從隊列的一端寫入數據,另一端讀出,如下圖示:

1.3 管道的優點

簡單

1.4 管道的缺點

只能單向通信,如果需要雙向通信則需要建立兩個管道;只能應用於具有血緣關係的進程,如父子進程;緩衝區大小受限,通常為1頁,即4k;

▋**2. 管道的創建**

管道創建三步曲:

a. 父進程調用pipe函數創建管道;

b. 父進程調用fork函數創建子進程;

c. 父進程關閉fd[0],子進程關閉fd[1];

具體如下圖所示:

▋**3. 管道的讀寫行為**

a. 管道的緩衝區大小固定為4k,所以如果管道內數據已經寫滿,則無法再寫入數據,進程的write調用將阻塞,直到有足夠的空間再寫入數據;

b. 管道的讀動作比寫動作要快,數據一旦被讀走了,管道將釋放相應的空間,以便後續數據的寫入。當所有的數據都讀完之後,進程的read()調用將阻塞,直到有數據再次寫入。

▋**4. 例程**

父子間通信:

<code> 1#include 2#include 3#include 4#include 5 6int main() 7{ 8 int fd[2]; 9 pid_t pid; 10 char buf[1024]; 11 char *data = "hello world!"; 12 13 /* 創建管道 */ 14 if (pipe(fd) == -1) { 15 printf("ERROR: pipe create failed!\n"); 16 return -1; 17 } 18 19 pid = fork(); 20 if (pid == 0) { 21 /* 子進程 */ 22 close(fd[1]); // 子進程讀取數據,關閉寫端 23 read(fd[0], buf, sizeof(buf)); // 從管道讀數據 24 printf("child process read: %s\n", buf); 25 close(fd[0]); 26 } else if (pid > 0) { 27 /* 父進程 */ 28 close(fd[0]); //父進程寫數據,關閉讀端 29 write(fd[1], data, strlen(data)); // 向管道寫數據 30 printf("parent process write: %s\n", data); 31 close(fd[1]); 32 } 33 34 return 0; 35} /<code>

兄弟間通信:

<code> 1#include 2#include 3#include 4#include 5#include 6 7int main () 8{ 9 int fd[2]; 10 int i = 0; 11 pid_t pid; 12 char buf[1024]; 13 char *data = "hello world!"; 14 15 /* 創建管道 */ 16 if (pipe(fd) == -1) { 17 printf("ERROR: pipe create failed!\n"); 18 return -1; 19 } 20 21 for (i = 0; i < 2; i++) { 22 pid = fork(); 23 if (pid == -1) { 24 printf("ERROR: fork error!\n"); 25 return -1; 26 } else if (pid == 0) { 27 break; 28 } 29 } 30 31 /* 通過i來判斷創建的子進程及父進程 */ 32 if (i == 0) { 33 /* 第一個子進程,兄進程 */ 34 close(fd[0]); // 兄進程向弟進程寫數據,關閉讀端 35 write(fd[1], data, strlen(data)); 36 printf("elder brother send: %s\n", data); 37 close(fd[1]); 38 } else if (i == 1) { 39 /* 第二個子進程,弟進程 */ 40 close(fd[1]); 41 read(fd[0], buf, sizeof(buf)); 42 printf("younger brother receive: %s\n", buf); 43 close(fd[0]); 44 } else { 45 /* 父進程 */ 46 close(fd[0]); 47 close(fd[1]); 48 for (i = 0; i < 2; i++) { 49 wait(NULL); 50 } 51 } 52 53 return 0; 54} /<code>

> 2020 精選 阿里/騰訊等一線大廠 面試、簡歷、進階、電子書 「**良許Linux**」後臺回覆「**資料**」免費獲取

#### 看完的都是真愛,點個贊再走唄?您的「三連」就是良許持續創作的最大動力!

1. 關注**原創**「**良許Linux**」,第一時間獲取最新Linux乾貨!

2. 後臺回覆【資料】【面試】【簡歷】獲取精選一線大廠面試、自我提升、簡歷等資料。

3. 關注我的博客:[lxlinux.net](http://www.lxlinux.net)