天天看點

Linux 程序間通信 | 管道

管道的基本概述及其特性

管道是Unix中最古老的程序間通信的形式。 我們把從一個程序連接配接到另一個程序的一個資料流稱為一個“管道”

特性:半雙工通信---可以選擇方向的單向通信。

本質:在核心中開辟的一段緩沖區(核心空間中的一塊記憶體)

原理:多個程序通過通路同一塊核心中的緩沖區實作通信

分類:

        匿名管道:緩沖區沒有辨別符,隻能用于具有親緣關系的程序間通信

        命名管道:緩沖區具有辨別符(在檔案系統中會顯示一個管道檔案),可用于同一主機上任意的程序間通信。

匿名管道

管道的建立

函數原型

#include <unistd.h>
       int pipe(int pipefd[2]);
           

pipefd[0]:用于讀

        pipefd[1]:用于寫

        傳回值:成功傳回0 失敗傳回-1;。

父子程序間實作匿名管道通信

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main()
{
    int pipefd[2];

    int ret = pipe(pipefd);
    if (ret < 0)
    {
        perror("pipe");
        return -1;
    }

    ret = fork();
    if (ret < 0)
    {
        perror("fork");
        return -1;
    }
    else if (ret == 0)
    {
        //child  read
        close(pipefd[1]);
        char buf[1024] = {0};
        ret = read(pipefd[0], buf, 1023);
        if (ret < 0)
        {
            perror("read");
            return -1;
        }
        printf("child read:%s\n", buf);
        close(pipefd[0]);
    }
    //父程序  write
    close(pipefd[0]);

    printf("father write:");
    char buf[128] = {0};
    fgets(buf, 127, stdin);
    write(pipefd[1], buf, strlen(buf));

    close(pipefd[1]);

    wait(NULL);
    return 0;
}
           
Linux 程式間通信 | 管道

命名管道

命名管道的辨別符就是一個可見于檔案系統的管道類型檔案。 多個程序通過打開同一個管道檔案,通路同一塊核心中的緩沖區實作通信,當mkfifo一個管道檔案後 核心不會立刻開辟記憶體 而是等到進行讀寫操作的時候會進行記憶體開辟。

 指令操作:mkfifo filename 建立一個命名管道檔案

 函數操作:int mkfifo(const char *pathname, mode_t mode);

                mode 建立權限

                傳回值 成功傳回0 失敗傳回-1;

 建立一個命名管道進行程序間通信

//write.c
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>

int main()
{
    int ret = mkfifo("./test.fifo", 0664);
    if (ret < 0 && errno != EEXIST)
    {
        perror("mkfifo");
        return -1;
    }

    int fd = open("./test.fifo", O_WRONLY);
    if (fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("creat fifo!!\n");
    char buf[1024] = {0};
    while (1)
    {
        //sprintf(buf,"%s",stdin);
        //scanf("%s",buf);
        fgets(buf,1023,stdin);
        ret = write(fd, buf, strlen(buf));
        if(ret<0)
        {
            perror("write");
            return -1;
        }
    }
    close(fd);
    return 0;
}
           
//read.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <memory.h>

int main()
{
    int ret = mkfifo("./test.fifo", 0664);
    if (ret < 0 && errno != EEXIST)
    {
        perror("mkfifo");
        return -1;
    }

    int fd = open("./test.fifo", O_RDONLY);
    if (fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("creat fifo!!\n");
    char buf[1024] = {0};
    while (1)
    {
        ret = read(fd, buf, 1023);
        if (ret < 0)
        {
            perror("read");
            return -1;
        }
        printf("%s\n", buf);
        memset(buf, 0, 1024);
    }
    close(fd);
    return 0;
}
           
Linux 程式間通信 | 管道

管道的讀寫特性

匿名管道

特性:隻能用于具有親緣關系的程序間通信 因為緩沖區沒有辨別符,無法被其它程序找到,隻能通過子程序父程序的方式擷取到操作句柄實作通信。

讀寫特性:若管道中沒有資料則read會阻塞,若管道中資料滿了,則write會阻塞。

所有的管道讀端被關閉,則繼續write則會觸發異常導緻程序崩潰退出  哪個程序去寫資料哪個程序就會崩潰(原因會給程序發送SIGPIPE信号)。

所有的管道寫端被關閉,則繼續read則會讀完資料後傳回0,不再阻塞。

管道提供位元組流傳輸服務:有序的,可靠的,基于連接配接的流式傳輸。

命名管道

打開特性:若是以隻讀方式打開管道檔案則會阻塞,直到管道被其它程序以寫的方式打開 則會繼續,反之亦是如此。

特性:半雙工通信 可以選擇方向的單向通信

管道提供位元組流傳輸服務 ---- 有序的 可靠的 基于連接配接的一種流式傳輸

基于連接配接:所有read關閉則write異常,所有write關閉則read傳回

互斥的展現:對管道進行寫入操作大小不超過PIPE_BUF-4096大小,則保證操作的原子性

同步的展現:若管道沒有資料則read阻塞 若管道資料滿了 則write阻塞。

生命周期随程序---不人為幹預,所有打開管道的程序退出了後則管道緩沖區被釋放。 

同步與互斥

           互斥:同一時間程序對臨界資源的唯一通路實作通路操作安全

            同步:通過一些條件判斷讓程序對臨界資源的通路更加合理有序

臨界資源:公共資源,大家都能通路到的資源

臨界區:對臨界資源通路的這段代碼區域

繼續閱讀