1. 程式人生 > >程序同步-管道和IPC

程序同步-管道和IPC

參考文章:https://blog.csdn.net/bit_clearoff/article/details/55105816

管道是程序間通訊的方式之一,是在程序之間建立一個實現資料流通的通道,用來快取要傳輸的資料。

每個管道有兩個檔案描述符,寫和讀。

例:父子程序通訊,關閉無關的檔案描述符,子->父,子關閉讀,父關閉寫。

管道特點:

1.管道沒有名字。

2.管道是半雙工的,資料單向流動,雙向通訊需要兩個管道。

3.只能擁有有親屬關係的程序之間。

4.單獨構成檔案系統,並且只存在記憶體中。

5.緩衝區大小有限。

6.資料的寫入和讀出:一個程序寫入的從管道另一邊讀出,寫入在管道末尾,讀出在緩衝區頭部。

7.管道傳送的是無格式位元組流。

管道建立

void pipe_init()
{
    /*
      通過pipe建立一個管道,引數是一個int型pipefd[2],分別代表讀和寫。
     成功返回0,反之-1。
     */
    int fd[2];
    char readbuffer[20];
    char writebuffer[]="hello world";
    int temp=pipe(fd);
    if(temp<0)
    {
        cout<<"pipe creat error"<<endl;
        exit(0);
    }
    write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料
    read(fd[0], readbuffer, sizeof(writebuffer));// 讀出 size和write一樣
    cout<<"管道讀出的資料:"<<readbuffer<<endl;//輸出讀到的資料
    cout<<"管道的讀檔案符fd[0]:"<<fd[0]<<" 管道的寫檔案符fd[0]:"<<fd[1]<<endl;
    //結束時要關閉檔案描述符
    close(fd[0]);
    close(fd[1]);
}

 

父子程序之間通訊

(不知道為啥必須在if裡面寫fork 如果在外面建立pid read讀區會出錯誤)

void pid_pipe1()//在父子程序中進行管道通訊 父程序讀 子程序寫
{
    int fd[2];
    //char readbuffer[20];
    //char writebuffer[]="helloworld";
    pid_t pid;
    //pid=fork();
    int pe=pipe(fd);
    if(pe<0)
    {
        cout<<"pipe failed"<<endl;
        exit(1);
    }
    if(fork()==0)//child 不知道為啥必須在if裡面寫fork 如果在外面建立pid read讀區會出錯誤
    {
        char writebuffer[12]="hello world";
        close(fd[0]);//子程序寫操作 把讀關了
        write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料
        //write(fd[1], &writebuffer, 1);//管道寫入資料
    }
    else//father
    {
        sleep(1);
        close(fd[1]);//父程序寫操作 把寫關了
        //char readbuffer[20];
        char readbuffer[12];
        read(fd[0], readbuffer, 12);// 讀出 size和write一樣
        cout<<"父程序中,管道讀出的資料:"<<(readbuffer)<<endl;//輸出讀到的資料
        //printf("%s",readbuffer);
    }
    exit(0);
}

Linux的命名管道

命名管道和管道一樣,都是實實在在的檔案,但兩者的區別在於,命名管道又一個路徑名與之關聯。管道的檔案是不公開的,管道通訊只是存在於有親屬關係的程序之中,但是和建立命名管道的程序沒有親屬關係的程序,只要可以訪問路徑,兩個程序就可以實現通訊。

命名管道的工作方式

1 命名管道由shell建立,將資料從一條管道傳遞到另一條,無需建立中間臨時檔案。

2 用於客戶程序和服務程序的應用程式,在客戶程序和伺服器程序之間傳遞資料。

ps:由於命名管道是檔案格式,同一個名字的檔案建立成功之後就不能再建立了。

 

void fun1(int argc, const char * argv[])//使用mkfifo函式建立命名管道
{
    mode_t mode=0755;//檔案許可權設定
    if(argc!=2)
    {
       // cout<<"請輸入正確的檔案引數"<<endl;
        //exit(0);
    }
    //成功返回0 反之返回-1 第一個引數是命名管道的檔案路徑名字
    if(mkfifo("mingmingguandao", mode)==0)
    {
        cout<<"命名管道建立成功"<<endl;
        //cout<<"建立失敗"<<endl;
        //exit(1);
    }
    else
    {
        cout<<"建立失敗"<<endl;
        exit(1);
    }
}

建立失敗的原因是已經建立成功,檔案已經存在。

匿名管道(普通管道)完整程式和參考程式碼

//
//  main.cpp
//  Linux程序同步-管道和IPC
//
//  Created by 藍貓 on 2018/11/8.
//  Copyright © 2018年 藍貓. All rights reserved.
//

#include <iostream>
#include <sys/types.h>
#include <unistd.h>

using namespace std;
/*
 管道是程序間通訊的方式之一,是在程序之間建立一個實現資料流通的通道,用來快取要傳輸的資料。
 每個管道有兩個檔案描述符,寫和讀。
 例:父子程序通訊,關閉無關的檔案描述符,子->父,子關閉讀,父關閉寫。
管道特點:
1.管道沒有名字。
2.管道是半雙工的,資料單向流動,雙向通訊需要兩個管道。
3.只能擁有有親屬關係的程序之間。
4.單獨構成檔案系統,並且只存在記憶體中。
5.緩衝區大小有限。
6.資料的寫入和讀出:一個程序寫入的從管道另一邊讀出,寫入在管道末尾,讀出在緩衝區頭部。
7.管道傳送的是無格式位元組流。
 
 */

void pipe_init()
{
    /*
      通過pipe建立一個管道,引數是一個int型pipefd[2],分別代表讀和寫。
     成功返回0,反之-1。
     */
    int fd[2];
    char readbuffer[20];
    char writebuffer[]="hello world";
    int temp=pipe(fd);
    if(temp<0)
    {
        cout<<"pipe creat error"<<endl;
        exit(0);
    }
    write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料
    read(fd[0], readbuffer, sizeof(writebuffer));// 讀出 size和write一樣
    cout<<"管道讀出的資料:"<<readbuffer<<endl;//輸出讀到的資料
    cout<<"管道的讀檔案符fd[0]:"<<fd[0]<<" 管道的寫檔案符fd[0]:"<<fd[1]<<endl;
    //結束時要關閉檔案描述符
    close(fd[0]);
    close(fd[1]);
}
void pid_pipe1()//在父子程序中進行管道通訊 父程序讀 子程序寫
{
    int fd[2];
    //char readbuffer[20];
    //char writebuffer[]="helloworld";
    pid_t pid;
    //pid=fork();
    int pe=pipe(fd);
    if(pe<0)
    {
        cout<<"pipe failed"<<endl;
        exit(1);
    }
    if(fork()==0)//child
    {
        char writebuffer[12]="hello world";
        close(fd[0]);//子程序寫操作 把讀關了
        write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料
        //write(fd[1], &writebuffer, 1);//管道寫入資料
    }
    else//father
    {
        sleep(1);
        close(fd[1]);//父程序寫操作 把寫關了
        //char readbuffer[20];
        char readbuffer[12];
        read(fd[0], readbuffer, 12);// 讀出 size和write一樣
        cout<<"父程序中,管道讀出的資料:"<<(readbuffer)<<endl;//輸出讀到的資料
        //printf("%s",readbuffer);
    }
    exit(0);
}
int fun1()
{
    int filedes[2];
    //pid_t pid;
    //pid=fork();
    char buf[10];
    char out[10];
    pipe(filedes);
    if(fork() ==0)
    {
        close(filedes[0]);//子程序寫操作 把讀關了
        sprintf(buf,"%s","ab");
        write(filedes[1],buf,sizeof(buf));
    }
    else
    {
        close(filedes[1]);//子程序寫操作 把讀關了
        read(filedes[0],out,sizeof(buf));
        printf("%s\n",out);
    }
    return 0;
}
int fun2()
{
    //create pipe
    int fd[2]={0,0};
    if(pipe(fd)!=0){
        //create false
        perror("pipe");
        exit(1);
    }
    // pipe create success
    pid_t id=fork();
    if(id==0){
        //child -->write fd[1]
        printf("Child\n");
        sleep(2);
        const char* msg="Hello,leap\n";
        close(fd[0]);
        int count=3;
        while(count--){
            ssize_t size=write(fd[1],msg,strlen(msg));
            printf("size:%d\n",size);
            //if(count--){
            //  sleep(1);
            //}
            sleep(1);
            printf("child is writing...\n");
        }
        close(fd[1]);
        exit(0);
    }
    else{
        //father -->read fd[0]
        printf("Father\n");
        sleep(2);
        close(fd[1]);
        char buf[1024];
        int count=3;
        while(1){
            ssize_t Len=read(fd[0],buf,1024);
            //printf("Len::%d\n",Len);
            printf("Father is reading...\n");
            if(Len>0){
                //read success
                buf[Len]='\0';
                printf("child say:%s",buf);
            }
            else if(Len==0){
                //read end of file
                printf("Read the end of pipe\n");
                break;
            }
            else{
                perror("read");
                exit(1);
            }
        }
        close(fd[0]);
        int status=0;
        pid_t _pid=waitpid(id,&status,0);
        if(_pid==id){
            printf("Wait success for child\n");
            printf("Exit code:%d,Exit signal:%d\n",(status>>8)&0xff,status&0xff);
        }
        else{
            perror("wait");
        }
        exit(0);
    }
    return 0;
}
int main(int argc, const char * argv[])
{
    pid_pipe1();
    //fun2();
    return 0;
}