進程間通信之管道通信

兩個程序之間傳遞數據的一種簡單方法是使用popen和pclose。

#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
    popen函數允許一個程序將另一個程序作為新進程來啟動,并可以傳遞數據給它或者通過它接收數據。command字符串是要運行的程序名和相應的參數。type必須是"r"或"w"。如果type是"r",被調程序的輸出就可以被調用程序使用,調用程序利用popen函數返回的FILE *文件流指針,可以讀取被調程序的輸出;如果type是"w",調用程序就可以向被調程序發送數據,而被調程序可以在自己的標準輸入上讀取這些數據。pclose函數只在popen啟動的進程結束后才返回。如果調用pclose時它仍在運行,pclose將等待該進程的結束。
#include <stdio.h>#define SIZE 1024*100int main()
{FILE *fp = popen("ps -ef", "r");if (fp == NULL){perror ("popen");return -1;}char buf[SIZE] = {0};int ret = fread(buf, sizeof(char), SIZE-1, fp);// printf ("讀到的數據:\n %s\n", buf);FILE *fp2 = popen("grep a.out", "w");if (fp2 == NULL){perror ("popen");return -1;}fwrite (buf, sizeof(char), ret, fp2);printf ("寫入完成\n");pclose (fp);pclose (fp2);return 0;
}

管道是單向的、先進先出的,它把一個進程的輸出和另一個進程的輸入連接在一起。一個進程(寫進程)在管道尾部寫入數據,另一個進程(讀進程)從管道的頭部讀出數據。管道包括無名管道和有名管道兩種,前者用于父進程和子進程間的通信,后者可用于運行于同一系統中的任意兩個進程間的通信。
無名管道由pipe( )函數創建:

int pipe(int filedis[2]);

當一個管道建立時,它會創建兩個文件描述符:filedis[0]fi用于讀管道,ledis[1]
用于寫管道。
這里寫圖片描述
管道用于不同進程間通信。通常先創建一個管道,在通過fork函數創建一個子進程,該子進程會繼承父進程所創建的管道描述符。必須在系統調用fork()前調用pipe(),否則子進程將不會繼承文件描述符。

1、單個進程中的管道

#include <stdio.h>
#include <unistd.h>#define SIZE 1024*100int main()
{int fd[2];int ret = pipe(fd);if (ret == -1){perror ("pipe");return -1;}ret = write (fd[1], "hello", 5);printf ("寫入 %d 個字節\n", ret);char ch;while (1){// 如果管道里面沒有數據可讀,read會阻塞ret = read (fd[0], &ch, 1);if (ret == -1){perror ("read");break;}printf ("讀到 %d 字節: %c\n", ret, ch);}close (fd[0]);close (fd[1]);return 0;
}

2、父子進程通過管道進行通信

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>#define SIZE 1024// 子進程通過管道從父進程接收數據
void child_do(int *fd)
{// 將管道的寫端關閉close (fd[1]);char buf [SIZE];while (1){// 從父進程讀取數據int ret = read (fd[0], buf, SIZE-1);if (ret == -1){perror ("read");break;}buf[ret] = '\0';printf ("子進程讀到 %d 字節數據: %s\n", ret, buf);}// 關閉讀端close (fd[0]);
}// 父進程通過管道向子進程發送數據
void father_do(int *fd)
{// 將管道讀端關閉close (fd[0]);char buf[SIZE];while (1){fgets (buf, SIZE, stdin);// 向子進程發送數據int ret = write (fd[1], buf, strlen(buf));printf ("父進程發送了 %d 字節數據\n", ret);}// 關閉寫端close (fd[1]);
}int main()
{int fd[2];// 創建管道int ret = pipe(fd);if (ret == -1){perror ("pipe");return -1;}// 創建子進程pid_t pid = fork();switch (pid){case -1:perror ("fork");break;case 0:   // 子進程child_do(fd);break;default:father_do(fd);break;}return 0;
}

3、父子進程通過管道實現文件復制

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>#define SIZE 1024// 子進程通過管道從父進程接收數據
void child_do(int *fd)
{// 將管道的寫端關閉close (fd[1]);int fd_write = open ("2.mmap", O_WRONLY|O_CREAT, 0777);if (fd_write == -1){perror ("open");return;}int ret;char buf [SIZE];// read 從管道讀數據,如果管道沒有數據可讀,read 會阻塞// 如果 管道的寫端 被關閉, read 返回 0while (ret = read (fd[0], buf, SIZE)){if (ret == -1){perror ("read");break;}// 把從父進程接收的數據寫入到新文件中write (fd_write, buf, ret);}printf ("文件復制完成\n");// 關閉讀端close (fd[0]);close (fd_write);
}// 父進程通過管道向子進程發送數據
void father_do(int *fd)
{// 將管道讀端關閉close (fd[0]);int fd_read = open ("1.mmap", O_RDONLY);if (fd_read == -1){perror ("open");return;}int ret;char buf[SIZE];while (ret = read (fd_read, buf, SIZE)){if (ret == -1){perror ("read");break;}// 把讀到的內容發送給子進程write (fd[1], buf, ret);}// 關閉寫端close (fd[1]);close (fd_read);
}int main()
{int fd[2];// 創建管道int ret = pipe(fd);if (ret == -1){perror ("pipe");return -1;}// 創建子進程pid_t pid = fork();switch (pid){case -1:perror ("fork");break;case 0:   // 子進程child_do(fd);break;default:father_do(fd);break;}return 0;
}

4、管道讀端關閉,寫端繼續寫數據

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>#define SIZE 1024// 子進程通過管道從父進程接收數據
void child_do(int *fd)
{close (fd[1]);close (fd[0]);
}void father_do(int *fd)
{// 將管道讀端關閉close (fd[0]);printf ("等待子進程關閉讀端\n");sleep(2);// 所有讀端都關閉了,寫端繼續往管道寫入數據// 如果管道所有的讀端都被關閉,繼續寫數據系統默認的操作是使程序退出write (fd[1], "hello", 5);printf ("11111111111111111111111111111111\n");// 關閉寫端close (fd[1]);
}int main()
{int fd[2];// 創建管道int ret = pipe(fd);if (ret == -1){perror ("pipe");return -1;}// 創建子進程pid_t pid = fork();switch (pid){case -1:perror ("fork");break;case 0:   // 子進程child_do(fd);break;default:father_do(fd);break;}return 0;
}

以上是無名管道常用的一些操作。

命名管道(FIFO)和無名管道基本相同,但也有不同點:無名管道只能由父子進程使用;但是通過命名管道,不相關的進程也能交換數據。

命名管道具有很好的使用靈活性,表現在:

1) 既可用于本地,又可用于網絡。

2) 可以通過它的名稱而被引用。

3) 支持多客戶機連接。

4) 支持雙向通信。

5) 支持異步重疊I/O操作。

1、創建命名管道

#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);

pathname: FIFO文件名
mode:屬性(同文件操作)

一旦創建了一個FIFO,就可用open打開它,一般的文件訪問函數(close、read、write等)都可用于FIFO。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>int main()
{int ret = mkfifo("/home/mkfifo", 0777);if (ret == -1){perror ("mkfifo");return -1;}return 0;
}

2、命名管道的傳輸
當打開FIFO時,非阻塞標識(O_NONBLOCK)將對以后的讀寫產生影響:
1、沒有使用O_NONBLOCK:訪問要求無法滿足時進程將阻塞。如果試圖讀取空的FIFO,將導致進程阻塞。
2、使用O_NONBLOCK:訪問要求無法滿足時不阻塞,立刻出錯返回。errno是ENXIO。

寫入:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>#define SIZE 1024int main()
{int fd = open("/home/mkfifo", O_WRONLY);if (fd== -1){perror ("mkfifo");return -1;}char buf[SIZE];while (1){fgets (buf, SIZE, stdin);write (fd, buf, strlen(buf));}return 0;
}

讀取:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define SIZE 1024int main()
{int fd = open("/home/mkfifo", O_RDWR);if (fd == -1){perror ("mkfifo");return -1;}char buf[SIZE];while (1){int ret = read (fd, buf, SIZE);buf[ret] = '\0';printf ("讀到 %d 字節: %s\n", ret, buf);}return 0;
}

管道作為進程間通信的4種方式之一,他并不會保存數據,區別與共享內存。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448457.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448457.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448457.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue 各組件 使用 Demo

環境搭建 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 假設你已經通讀vue官方文檔&#xff08;文檔都沒讀一遍&#xff08;至少&#xff09;&#xff0c;那不建議動手擼碼&#xff…

Dropbox推獨立應用,公司估值已達100億美元

摘要&#xff1a;Dropbox剛獲得5億美元的新一輪融資&#xff0c;其估值已高達100億美元&#xff0c;現在又推出針對云服務的獨立應用Carousel&#xff0c;不久之后&#xff0c;還會有應用陸續推出&#xff0c;隨著美國前國務卿賴斯的加盟&#xff0c;Dropbox在云市場的表現異常…

SQL經典面試題(二)

有3個表S&#xff0c;C&#xff0c;SCS&#xff08;SNO&#xff0c;SNAME&#xff09;代表&#xff08;學號&#xff0c;姓名&#xff09; //主鍵&#xff1a;SNO //多個人&#xff0c;多門課 3張表 &#xff0c;SC 關系表C&#xff08;CNO&#xff0c;CNAME&#xff0c;…

進程間通信之信號he信號量

信號的篇幅較少&#xff0c;就把他和信號量放在一起了。先講講他們之間的區別&#xff1a; 1.信號&#xff1a;&#xff08;signal&#xff09;是一種處理異步事件的方式。信號時比較復雜的通信方式&#xff0c;用于通知接受進程有某種事件發生&#xff0c;除了用于進程外&…

開源當自強:我們不是“便宜貨”

之前人們爭相使用開源軟件&#xff0c;無非是因為它便宜、好用、易得&#xff0c;不過根據最新的開源軟件調查顯示&#xff0c;人們使用開源軟件最主要的原因還是看重它的高質量。 成本低是很過公司參與開源項目的最主要原因之一&#xff0c;而現在他們視開源是一條通往創新、省…

前端學習:Vue.js基本使用

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Vue教程文檔&#xff1a; https://cn.vuejs.org/v2/guide/ 定義 實例&#xff1a; new Vue() 掛載點: el 數據&#xff1a;data 模…

PWE

Obstacle Override Logic The obstacle override logic provides the possibility to override obstacle within a window movement by selective switching off the anti-trap functionality.轉載于:https://www.cnblogs.com/dannykong/p/11151813.html

進程間通信之消息隊列

一、什么是消息隊列 unix早期通信機制之一的信號能夠傳送的信息量有限&#xff0c;管道則只能傳送無格式的字節流&#xff0c;這無疑會給應用程序開發帶來不便。消息隊列&#xff08;也叫做報文隊列&#xff09;則克服了這些缺點。 消息隊列就是一個消息的鏈表。可以把消息看…

“ 愿我如星君如月,夜夜流光相皎潔 ...”

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 永遠相信愛情 ... 從一而終 ... --------------------------------------------------------------------------- 后記&#xff1a;2…

python內建函數和工廠函數的整理

內建函數參閱&#xff1a; https://www.cnblogs.com/pyyu/p/6702896.html 工廠函數&#xff1a; 本篇博文比較粗糙&#xff0c;后續會深入整理轉載于:https://www.cnblogs.com/qiang-upc/p/11155786.html

顯卡天梯圖:2014最新顯卡性能天梯圖

隨著電腦游戲的推廣&#xff0c;很多用戶都喜歡上了電腦網絡游戲&#xff0c;所以組裝電腦用戶在裝機的時候&#xff0c;會考慮電腦配置的游戲性能&#xff0c;要提高電腦配置游戲性能首要條件就是顯卡性能要強&#xff0c;如果顯卡性能不佳&#xff0c;那么其它方面性能再強&a…

進程間通信之分別用共享內存和信號量實現賣票

利用共享內存實現的賣票系統&#xff1a; 利用flag來保證同一時間只有一個程序使用內存&#xff0c;使用結束還原。 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <string.h> #include <…

shiro 的 @RequiresPermissions 注解使用

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 權限控制是shiro最核心的東西 Shiro權限聲明通常是使用以冒號分隔的表達式。一個權限表達式可以清晰的指定資源類型&#xff0c;允許的…

【顯卡天梯圖】2014年最新顯卡天梯圖 – 【迄今最全系列顯卡】

【顯卡天梯圖】2014年最新顯卡天梯圖 – 【迄今最全系列顯卡】 隨著電腦游戲的推廣&#xff0c;很多用戶都喜歡上了電腦網絡游戲&#xff0c;所以組裝電腦用戶在裝機的時候&#xff0c;會考慮電腦配置的游戲性能&#xff0c;要提高電腦配置游戲性能首要條件就是顯卡性能要強&am…

原理系列:Spark1.x 生態圈一覽

Spark生態圈&#xff0c;也就是BDAS&#xff08;伯克利數據分析棧&#xff09;&#xff0c;是伯克利APMLab實驗室精心打造的&#xff0c;力圖在算法&#xff08;Algorithms&#xff09;、機器&#xff08;Machines&#xff09;、人&#xff08;People&#xff09;之間通過大規模…

SpringMVC 注解 : @ModelAttribute

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 SpringMVC 注解 &#xff1a; ModelAttribute 的用法如上。 轉自&#xff1a;https://blog.csdn.net/lovesomnus/article/details/78873…

網絡編程項目(聊天室項目)

一、實現目標 一個在Linux下可以使用的聊天軟件&#xff0c;要求至少實現如下功能&#xff1a; 1. 采用Client/Server架構 2. Client A 登陸聊天服務器前&#xff0c;需要注冊自己的ID和密碼 3. 注冊成功后&#xff0c;Client A 就可以通過自己的ID和密碼登陸聊天服務器 4…

CPU天梯圖:2014年最新CPU性能天梯圖

用戶在組裝電腦的前期需要考慮怎么選擇適合自己的CPU&#xff0c;現在CPU性能強的比較貴&#xff0c;便宜的CPU性能又比較差&#xff0c;選擇性價比高并且適合自己的處理器還真是比較花心思。在2014年的時候&#xff0c;最主流熱門的AMD處理器是AMD A10-6800K&#xff0c;最新推…

解決: idea 修改 jsp 后,頁面刷新無效

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 idea 修改 jsp 后瀏覽器訪問無效。 解決&#xff1a;進入 idea 配置 修改部署方式&#xff1a; 修改 更新文件方式&#xff1a; OK了。

Python中的getpass模塊

getpass模塊用于輸入密碼時&#xff0c;隱藏密碼字符 代碼 import getpass name input("請輸入你的名字&#xff1a;") passwd getpass.getpass("請輸入你的密碼&#xff1a;")print (name,passwd)   首先我們要import引入getpass模塊&#xff0c;然后…