1. 程式人生 > >Linux---程序間通訊IPC之管道

Linux---程序間通訊IPC之管道

**程序間通訊(IPC):**是指在不同程序之間傳播或交換資訊。
**IPC的方式:**通常有管道(無名管道、命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等(Socket和Streams支援不同主機上的兩個程序IPC)
程序間通訊的目的:
**1.資料傳輸:**一個程序需要將它的資料發給另一個程序
**2.資源共享:**多個程序之間共享同樣的資源
**3.通知事件:**一個程序需要向另一個或一組程序傳送訊息,通知它(它們)傳送了啥(如程序終止要通知父程序)
**4.程序控制:**有些程序希望完全控制另一個程序的執行(如Debug程序),此時控制程序希望能夠攔截另一個程序的所有陷入和異常,並能夠及時知道它的狀態改變

管道

這裡寫圖片描述

把從一個程序連線到另一個程序的一個數據流稱為管道,本質上就是核心的一塊快取,一端寫進去,另一端讀
這段快取還是得在記憶體上開空間,需要MMU對映

匿名管道
fork之後,子程序會繼承父程序的檔案描述符,匿名管道適用於具有血緣關係的程序間通訊
這裡寫圖片描述

 - 管道內沒有資料,讀端發生阻塞,等待讀取有效資料
 - 管道被資料填滿,寫端發生阻塞,等待資料被讀走再寫入
 - 如果管道寫端的檔案描述符關閉,read會將管道內的資料讀完,然後返回0
 - 如果管道讀端的檔案描述符關閉,write會產生訊號SIGPIPE,然後write的程序退出
 - 當寫入的資料小於管道的容量,操作會有原子性,否則不會保證其原子性
 - 管道在使用者程式看起來就像一個開啟的檔案,向這個檔案讀寫資料其實是在讀寫核心緩衝區
 - 管道面向的是位元組流
 - 匿名管道用於具有血緣關係的程序間通訊
 - 管道基於檔案描述符,依賴於檔案
 - 與之相關的程序退出時,管道也會隨之被釋放,宣告週期隨程序

建立匿名管道

#include<unistd.h>
int pipe(int fd[2]);
//fd:檔案描述符陣列,fd[0]表示讀端,fd[1]表示寫端
//返回值:成功返回0,失敗返回錯誤碼
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
        int fd[2];
        if(pipe(fd)<0)//建立管道
        {
                perror("pipe");
                exit(0);
        i
        pid_t id=fork();//建立子程序
        if(id==0)
        {
                close(fd[0]);//關閉讀端
                const char* msg="hello father,i am your child";
                write(fd[1],msg,strlen(msg));//向管道里寫入資料
        }
        else
        {
                close(fd[1]);//關閉寫端
                char* buf[1024];
                ssize_t s=read(fd[0],buf,sizeof(buf));//從管道里讀取資料
                if(s>0)//讀到資料
                {
                        buf[s]=0;
                        printf("chile >> father : %s\n",buf);//輸出資料
                }
        }
        return 0;
}

這裡寫圖片描述
命名管道
命名管道其實還是個管道,本質上是一個檔案

建立命名管道

//命令建立
mkfifo filename
//函式建立
int mkfifo(const char* filename,mode_t mode);
//引數:filename命名管道的名字,mode其存取的許可權

write.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/stat.h>
int main()
{
        mkfifo("./mypipe",0644);//建立命名管道
        int wfd=open("xyz",O_RDONLY);//開啟一個檔案
        if(wfd==-1)
        {
                perror("open");
                return 1;
        }
        int rfd=open("./mypipe",O_WRONLY);//開啟管道
        if(rfd==-1)
        {
                perror("open");
                return 1;
        }
        char buf[1024];
        ssize_t s;
        while(s=read(wfd,buf,sizeof(buf))>0)//從檔案裡讀出來,寫到管道里,buf相當於是中間變數
        {
                write(rfd,buf,s);
        }
        close(wfd);
        close(rfd);
}

read.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
        int wfd=open("abc.bak",0_CREAT|O_WRONLY|O_TRUNC,0644);//
        if(wfd==-1)
        {
                perror("open");
                return 1;
        }
        int rfd=open("./mypipe",O_RDONLY);//開啟命名管道
        if(rfd==-1)
        {
                perror("open");
                return 1;
        }
        char buf[1024];
        ssize_t s;
        while((s=read(rfd,buf,sizeof(buf)))>0)
        {
                write(wfd,buf,s);
        }
        close(wfd);
        close(rfd);
return 0;
}

匿名管道和命名管道的區別:

  • 匿名管道由pipe函式建立並開啟
  • 命名管道由mkfifo函式建立,開啟用open
  • FIFO與pipe之間唯一的區別在於他們建立與開啟的方式不同,一旦這些工作之後,他們具有相同的語義

如果有什麼問題,可以評論告訴我,望指導!