linux程式間通訊-----管道總結例項
主要內容:匿名管道,命令管道。(pipe, popen, mkfifo等函式)
管道簡介:
管道是程式之間通訊的一種方式,就相當於是兩個程式之間有一條地道,可以通過地道來傳遞資訊;
管道位於程式的地址空間之外;管道分為匿名管道和命名管道兩種;匿名管道是由pipe來建立的,命名管道是由mkfifo來建立的;
#include <unistd.h>
int pipe(int pipefd[2]);
返回兩個描述符:pipefd[0]是管道的讀端,pipefd[1]是管道的寫端;
下面是一個父子程式利用管道通訊的例項:
main函式建立兩個管道,並用fork生成一個子程式,客戶端作為父程式執行,伺服器則作為子程式執行。第一個管道用於從客戶向伺服器傳送路徑名, 第二個管道用於從伺服器向客戶傳送該檔案的內容。
客戶端寫pipe1[1]-----pipe1[0]伺服器讀
伺服器寫pipe2[1]-----pipe2[0]客戶端讀
客戶端寫pipe1[1]-----pipe1[0]伺服器讀
伺服器寫pipe2[1]-----pipe2[0]客戶端讀
/*************************************************************************
> File Name: mainpipe.c
> Author:
> Mail:
> Created Time: 2016年04月20日 星期三 22時25分15秒
************************************************************************/
/*
* main函式建立兩個管道,並用fork生成一個子程式
* 客戶端作為父程式執行,伺服器則作為子程式執行
* 第一個管道用於從客戶向伺服器傳送路徑名
* 第二個管道用於從伺服器向客戶傳送該檔案的內容
*
* cin --客戶端寫pipe1[1]-----pipe1[0]伺服器讀
* 伺服器寫pipe2[1]-----pipe2[0]客戶端讀
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
//伺服器從rfd中讀取檔案的名字,向wfd中寫入檔案的內容
void server(int rfd, int wfd)
{
char fileName[1024];
char fileContent[2048];
memset(fileName, 0, 1024);
memset(fileContent, 0, 2048);
//從rfd中讀取檔案的名字,
int n = read(rfd, fileName, 1024);
fileName[n] = 0;
printf("server receive the file name is %s\n", fileName);
int filefd = open(fileName, O_RDONLY);//開啟檔案
if(filefd < 0){
printf("open error\n");
return;
}
else{//讀取檔案的內容,並寫入到wfd中
//讀取檔案的內容到fileContent中
int num = 0;
while((num = read(filefd, fileContent, 2048)) > 0){
printf("server read the fileContent is: %s", fileContent);
//將fileContent中的內容寫入到wfd中
write(wfd, fileContent, num);
}
}
close(filefd);
close(rfd);
close(wfd);
}
//客戶端從rfd中讀取檔案的內容,向wfd中寫入檔案的名字
void client(int rfd, int wfd)
{
char fileName[1024];
char fileContent[2048];
memset(fileName, 0, 1024);
memset(fileContent, 0, 2048);
printf("輸入檔名字:");
//從標準輸入輸入檔案的名字
fgets(fileName, 1024, stdin);
int len = strlen(fileName);
if(fileName[len-1] == '\n')
len--;
//向wfd中寫入檔案的名字
write(wfd, fileName, len);
printf("fileName = %s\n", fileName);
//從rfd中讀取檔案的內容
int n;
while((n = read(rfd, fileContent, 2048)) > 0){
printf("client receive the content is: %s", fileContent);
}
close(rfd);
close(wfd);
}
//主函式
int main()
{
//建立兩個管道.
int pipe1[2], pipe2[2];
int ret = pipe(pipe1);
if(ret < 0){
printf("pipe error\n");
return -1;
}
ret = pipe(pipe2);
if(ret < 0){
printf("pipe error\n");
return -1;
}
//建立一個子程式,作為伺服器,用於讀取管道1(pipe1[0])中的檔名,並將檔案的內容輸出到管道2的pipe2[1]中
pid_t child_pid = fork();
if(child_pid < 0){
printf("fork error\n");
return -1;
}
else if(child_pid > 0){//父程式
//關閉管道1的寫,關閉管道2的讀, pipe1[1], pipe2[0]
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0], pipe2[1]);
}
else if(child_pid == 0){//子程式
//關閉管道1的讀,關閉管道2的寫, pipe1[0], pipe2[1]
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0], pipe1[1]);
}
waitpid(child_pid, NULL, 0);//等待子程式退出
return 0;
}
執行結果為:
root@linux_ever:~/linux_ever/process_thread/ch4# ./mainpipe
輸入檔名字:./data
fileName = ./data
server receive the file name is ./data
server read the fileContent is: file content linuxever
client receive the content is: file content linuxever
有名管道(也稱為FIFO):
有名管道用mkfifo函式建立。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)
建立命名管道成功返回0;引數是一個pathname是建立的FIFO管道檔案的名字;mode使用者許可權是標識位,比如是0644;建立了一個管道檔案之後,要用它和其它程式通訊的時候需要再開啟該檔案open;
命名管道的開啟規則
如果當前開啟操作是為讀而開啟FIFO時1:O_NONBLOCK disable:阻塞直到有相應程式為寫而開啟該FIFO
2:O_NONBLOCK enable:立刻返回成功
如果當前開啟操作是為寫而開啟FIFO時
1:O_NONBLOCK disable:阻塞直到有相應程式為讀而開啟該FIFO
2:O_NONBLOCK enable:立刻返回失敗,錯誤碼為ENXIO
//outfd = open("fifop", O_WRONLY | O_NONBLOCK);//非阻塞寫
outfd = open("fifop", O_WRONLY ); //阻塞模式
例如:
1:一個程式開啟命名管道寫,預設是阻塞的方式開啟;如果該管道沒有另外的程式開啟讀,則該程式阻塞在寫開啟,直到有程式讀開啟;
2:一個程式開啟命名管道讀,預設是阻塞的方式開啟;如果該管道沒有另外的程式開啟寫,則該程式阻塞在讀開啟,直到有程式寫開啟;
一般以阻塞方式開啟,如果是以非阻塞方式開啟的話,每次從該檔案讀取資料的時候會立刻返回,哪怕是沒有資料;
命名管道和匿名管道區別:
1:管道應用的一個限制就是隻能在具有共同祖先(具有親緣關係)的程式間通訊。2:如果我們想在不相關的程式之間交換資料,可以使用FIFO檔案來做這項工作,它經常被稱為命名管道。
3:命名管道是一種特殊型別的檔案;
管道可以在父子程式之間傳遞資料
管道可以在父子程式之間傳遞資料,利用的是fork呼叫之後兩個管道檔案描述符pipefd[0]和pipefd[1]都保持開啟。這樣就可以實現父程式通過管道向子程式傳遞資料,或者子程式通過管道向父程式傳遞資料。
如果是想雙向傳輸資料的話,可以建立兩個管道。也可以通過socketpair建立一個全雙工的管道。
例子1:父程式通過匿名和子程式通訊,父程式向匿名管道寫入資料,子程式從匿名管道讀出資料並輸出到標準輸出上面
/*************************************************************************
> File Name: pipe1.cpp
> Author:
> Mail:
> Created Time: 2015年12月20日 星期日 19時48分57秒
************************************************************************/
#include<iostream>
#include <unistd.h>
#include <cstdlib>
#include <fcntl.h>
#include <string>
#include <sys/wait.h>
#include <string.h>
using namespace std;
/*
1:父程式建立一個管道, 0-read, 1-write
2:父程式建立一個子程式
3:讓父程式向管道中寫入資訊,子程式從管道讀取資訊;從標準輸入寫入到管道中
4:子程式將讀取的資訊輸出到標準輸出上面
*/
int main()
{
int pipefd[2];
char buff[1024];
memset(buff, 0, 1024);
int ret = pipe(pipefd);
if(ret != 0){
cerr << "pipe error..." << endl;
exit(-1);
}
pid_t pid = fork();
if(pid < 0){
cerr << "fork error..." << endl;
exit(-1);
}
else if(pid == 0){
//關閉管道的寫端
close(pipefd[1]);
int ret = 0;
cout << "This is child process...." << endl;
while(1){
ret = read(pipefd[0], (void *)buff, 1024);
if(ret == 0){
cout << "end of read.." << endl;
exit(0);
}
cout << "child read: ";
cout << buff << endl;
memset(buff, 0, 1024);
}
close(pipefd[0]);
}
else if(pid > 0){
close(pipefd[0]);
cout << "This is parent process...." << endl;
while(cin.getline(buff, 1024)){
cout << "parent write: ";
cout << buff << endl;
write(pipefd[1], buff, 1024);
memset(buff, 0, 1024);
}
close(pipefd[1]);
wait(NULL);
}
exit(0);
}
例子2:使用命名管道例項
程式1建立命名管道myfifo,並以阻塞方式寫開啟,程式1從標準輸入獲得資料並寫入到命名管道中;
程式2以阻塞方式讀開啟該命名管道檔案myfifo,程式2從該命名管道中讀取資料並輸出到標準輸出上;
程式1:write_fifo.cpp
/*************************************************************************
> File Name: write_fifo.cpp
> Author:
> Mail:
> Created Time: 2015年12月20日 星期日 20時53分29秒
************************************************************************/
#include<iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdlib>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
using namespace std;
/*
1:建立命名管道
2:從標準輸入輸入內容到buffer中
3:開啟命名管道,將buffer中的內容寫入到命名管道中
*/
int main()
{
int ret = mkfifo("myfifo", 0666);
if(ret < 0){
cerr << "mkfifo error..." << endl;
exit(-1);
}
char buff[1024];
memset(buff, 0, 1024);
int wrfd;
cout << "wating for another process open the myfifo to reading..."<< endl;
wrfd = open("myfifo", O_WRONLY);
if(wrfd == -1){
cerr << "open error..." << endl;
exit(-1);
}
pid_t pid = getpid();
cout << "process " << pid << " write: ";
while(cin.getline(buff, 1024)){
write(wrfd, buff, strlen(buff));
memset(buff, 0, 1024);
cout << "process " << pid << " write: ";
}
close(wrfd);
exit(0);
}
程式2:read_fifo.cpp
/*************************************************************************
> File Name: write_fifo.cpp
> Author:
> Mail:
> Created Time: 2015年12月20日 星期日 20時53分29秒
************************************************************************/
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdlib>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
using namespace std;
/*
1:建立命名管道
2:從標準輸入輸入內容到buffer中
3:開啟命名管道,將buffer中的內容寫入到命名管道中
*/
int main()
{
char buff[1024];
memset(buff, 0, 1024);
int rdfd;
int ret = 0;
rdfd = open("myfifo", O_RDONLY);
if(rdfd < 0){
cout << "open error..." << endl;
exit(-1);
}
cout << "waiting for reading...\n";
while(1){
ret = read(rdfd, buff, 1024);
if(ret == 0){
cerr << "end of read..." << endl;
break;
}
cout << "process "<< getpid() << " read: " << buff << endl;
memset(buff, 0, 1024);
}
close(rdfd);
exit(0);
}
下面圖中的myfifo檔案就是建立的命名管道,可以看到它的檔案型別為p開頭;
popen函式介紹:
標準I/O函式庫提供了popen函式,它建立一個管道並啟動另一個程式,該程式要麼從管道讀出標準輸入,要麼向該管道寫入標準輸出。
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
如果type為w,那麼呼叫該函式的程式寫入command的標準輸入。
例項:
/*************************************************************************
> File Name: popen.c
> Author:
> Mail:
> Created Time: 2016年04月22日 星期五 21時28分40秒
************************************************************************/
#include <stdio.h>
#include <string.h>
int main()
{
char buffer[1024];
char command[1024];
memset(buffer, 0, 1024);
memset(command, 0, 1024);
//輸入命令
printf("Input the command: ");
fgets(command, 1024, stdin);
//去除換行符號
int n = strlen(command);
if(command[n] = '\n'){
//command[n] = 0;//一定要賦值為0,不能是'0'
command[n] = '\0';//一定要賦值為0,或是'\0', 不能是'0'
}
//呼叫popen執行命令
//type='r',命令的標準輸出會輸出到管道,以fp引出來
FILE * fp = popen(command, "r");
if(fp == NULL){
printf("popen error\n");
return -1;
}
printf("輸出command的標準輸出: ");
//從fp中讀取命令的標準輸出
while(fgets(buffer, 1024, fp) != NULL)
fputs(buffer, stdout);
pclose(fp);
return 0;
}
執行結果:
輸出command的標準輸出: root@linux_ever:~/linux_ever/process_thread/ch4# ./readPopen
Input the command: cat data
輸出command的標準輸出: file content linuxever
root@linux_ever:~/linux_ever/process_thread/ch4# ./readPopen
Input the command: ls
輸出command的標準輸出: data
mainpipe
mainpipe.c
readPopen
readPopen.c
root@linux_ever:~/linux_ever/process_thread/ch4# ./readPopen
Input the command: ls -l
輸出command的標準輸出: 總用量 40
-rw-r--r-- 1 root root 23 4月 22 21:08 data
-rwxr-xr-x 1 root root 13377 4月 21 22:12 mainpipe
-rw-r--r-- 1 root root 3499 4月 21 22:12 mainpipe.c
-rwxr-xr-x 1 root root 9063 4月 22 22:08 readPopen
-rw-r--r-- 1 root root 1146 4月 22 22:08 readPopen.c
相關文章
- linux程式間通訊-----System V訊息佇列總結例項Linux佇列
- Linux 的程式間通訊:管道Linux
- linux 程式間通訊之管道Linux
- linux程式間通訊-----訊號總結Linux
- linux程式間通訊--管道(PIPE & FIFO)Linux
- Linux程式間通訊②:有名管道FIFOLinux
- linux程式間通訊-----System V共享記憶體總結例項Linux記憶體
- 程式間通訊(一)管道
- Linux 下的程式間通訊:使用管道和訊息佇列Linux佇列
- 溫故之.NET程式間通訊——管道
- 【IPC程式間通訊之二】管道PipeC程式
- Linux系統程式設計之程式間通訊方式:管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:管道(一)Linux程式設計
- Linux系統程式設計(11)——程式間通訊之有名管道Linux程式設計
- 管道流間的通訊
- 程序間通訊(1)-管道
- linux程式間通訊(IPC)小結Linux
- Linux系統程式設計之程式間通訊方式:命名管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:命名管道(一)Linux程式設計
- Linux程式執行緒學習筆記:程式間通訊 之 管道Linux執行緒筆記
- “Linux程式設計”小結(程式間通訊)Linux程式設計
- Android native程式間通訊例項-binder結合共享記憶體Android記憶體
- 3|程式間通訊--有名管道學習筆記筆記
- Linux程式間通訊Linux
- 程式間通訊——LINUXLinux
- Linux系統程式設計之程式間通訊方式:共享記憶體例項演示Linux程式設計記憶體
- 20.2、python程式間通訊——佇列和管道Python佇列
- Delphi 簡單命名管道在兩個程式間通訊
- LLinux系統程式設計(10)——程式間通訊之管道Linux程式設計
- linux程式和執行緒之間通訊方法和同步方法總結Linux執行緒
- Linux程式間通訊-eventfdLinux
- Linux程式間通訊1Linux
- Linux程式間通訊2Linux
- Android中活動間通訊總結Android
- 什麼是程式間通訊?Linux程式間通訊有幾種方式?Linux
- 程式間通訊是什麼?Linux程式間通訊有幾種方式?Linux
- linux 程式間通訊之FIFOLinux
- Linux程式之間如何通訊?Linux