鍍金池/ 教程/ Linux/ 匿名管道通訊
Linux 學(xué)習(xí)記錄--開機(jī)掛載錯誤
日志系統(tǒng)
數(shù)據(jù)流重定向
內(nèi)存交換空間的構(gòu)建
文件系統(tǒng)簡介
Linux 學(xué)習(xí)記錄--軟件安裝 RPM|SRPM|YUM
文件特殊權(quán)限
目錄配置 FHS
文件內(nèi)容查閱
Boot Loader
文件壓縮
Linux 學(xué)習(xí)記錄--文件權(quán)限
Linux 命令縮寫
命令與文件的查詢
文件|目錄的默認(rèn)權(quán)限與隱藏權(quán)限
shell script
服務(wù)
Linux 學(xué)習(xí)記錄--程序編譯與函數(shù)庫
正則表達(dá)式與其應(yīng)用
關(guān)機(jī)相關(guān)指令
shell
vim 與 vi 常用命令
系統(tǒng)調(diào)用:進(jìn)程控制
文件系統(tǒng)簡單操作
磁盤掛載與卸載
有名管道通訊
磁盤分區(qū),格式化與檢驗(yàn)
工作管理與進(jìn)程管理
匿名管道通訊
Linux 學(xué)習(xí)記錄--啟動流程
文件與目錄管理
管道命令
命名別名與歷史命令
文件備份|還原
shell變量
Linux 學(xué)習(xí)記錄--ACL 權(quán)限控制
內(nèi)核|內(nèi)核模塊編譯
文件管理相關(guān)系統(tǒng)編程

匿名管道通訊

管道是 Linux 支持的最初 Unix IPC 形式之一,具有以下特點(diǎn):
1.管道是半雙工的,數(shù)據(jù)只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;
2.只能用于父子進(jìn)程或者兄弟進(jìn)程之間(具有親緣關(guān)系的進(jìn)程);

什么是管道

管道對于管道兩端的進(jìn)程而言,就是一個文件,但它不是普通的文件,它不屬于某種文件系統(tǒng),而是自立門戶,單獨(dú)構(gòu)成一種文件系統(tǒng),并且只存在與內(nèi)存中。

數(shù)據(jù)的讀出和寫入

一個進(jìn)程向管道中寫的內(nèi)容被管道另一端的進(jìn)程讀出。寫入的內(nèi)容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀出數(shù)據(jù)。

管道的創(chuàng)建

#include int pipe(int fd[2])

管道兩端可分別用描述字 fd[0]以及 fd[1]來描述,需要注意的是,管道的兩端是固定了任務(wù)的。即一端只能用于讀,由描述字 fd[0]表示,稱其為管道讀端;另一端則只能用于寫,由描述字 fd[1]來表示,

管道的規(guī)則

  1. 當(dāng)管道內(nèi)容長度為0時,讀端將處于阻塞狀態(tài),等待寫端向管道寫入內(nèi)容
  2. 當(dāng)寫端數(shù)據(jù)長度小于緩沖區(qū)長度時,數(shù)據(jù)將以原子性寫入緩沖區(qū)。

對讀進(jìn)程來說:

  1. 當(dāng)寫端被關(guān)閉時,所有數(shù)據(jù)被讀出后,read 返回0。
  2. 當(dāng)寫端未被關(guān)閉時,所有數(shù)據(jù)被讀出后,讀端阻塞。

對寫進(jìn)程來說:

  1. 當(dāng)讀端關(guān)閉時,如寫端數(shù)據(jù)長度大于管道最大長度時,寫完管道長度時,產(chǎn)生信號 SIGPIPE 后退出程序。(以存入管道的數(shù)據(jù)讀進(jìn)程可以讀取到)
  2. 當(dāng)讀端未被關(guān)閉時,如寫端數(shù)據(jù)長度大于管道最大長度時,寫完管道長度時,寫端將處于阻塞狀態(tài)

    規(guī)則分析1

#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
int main() {
    int fd[2];
    pid_t cid;
    if (pipe(fd) == -1) {
        perror("管道創(chuàng)建失敗!");
        exit(1);
    }
    cid = fork();
    switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        close(fd[1]);
        char message[1000];
        int num = read(fd[0], message, 1000);
        printf("子進(jìn)程讀入的數(shù)據(jù)是:%s,長度是=%d", message, num);
        close(fd[0]);
        break;
    default:
        close(fd[0]);
        char *writeMsg = "父進(jìn)程寫入的數(shù)據(jù)!";
        sleep(10);//1
        write(fd[1], writeMsg, strlen(writeMsg));
        close(fd[1]);
        break;
    }
    return 0;
}

[root@ Release 18$] ps -C processcomm -opid,ppid,stat,cmd
PID PPID STAT CMD
5973 2488 S /root/workspace/processcomm/Release/processcomm
5976 5973 S /root/workspace/processcomm/Release/processcomm
=>讀端由于阻塞中,其所在進(jìn)程(子進(jìn)程)處于 sleep 狀態(tài)

控制臺輸出
父進(jìn)程工作 PID=5973,PPID=2488
子進(jìn)程工作 PID=5976,PPID=5973
子進(jìn)程讀入的數(shù)據(jù)是:父進(jìn)程寫入的數(shù)據(jù)!,長度是=27

規(guī)則分析2

switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[0]);
        const long int writesize=4000;
        char writeMsg[writesize];
        int i;
        for(i=0;i<writesize;i++)
        {
            writeMsg[i]='a';
        }
        int writenum=write(fd[1], writeMsg, strlen(writeMsg));
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[1]);
        wait(NULL);
        break;
    }

控制臺輸出
父進(jìn)程工作 PID=7072,PPID=2488
父進(jìn)程寫入的數(shù)據(jù)長度是=4001
子進(jìn)程工作 PID=7077,PPID=7072

規(guī)則分析3

switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[1]);
        char message[40001];
        int num = read(fd[0], message, 4001);
        printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d\n", num);
        num = read(fd[0], message, 4000);
        printf("子進(jìn)程再次讀入的數(shù)據(jù)長度是=%d", num);
        close(fd[0]);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[0]);
        const long int writesize = 4000;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize; i++) {
            writeMsg[i] = 'a';
        }
        int writenum = write(fd[1], writeMsg, strlen(writeMsg));
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[1]);
    //  wait(NULL);
        break;
    }

[root@ Release30$] ps -C processcomm -o pid,ppid,stat,cmd
PID PPID STAT CMD
=>讀寫進(jìn)程都已退出

控制臺輸出
父進(jìn)程工作 PID=8004,PPID=2488
父進(jìn)程寫入的數(shù)據(jù)長度是=4001
子進(jìn)程工作 PID=8009,PPID=1
子進(jìn)程讀入的數(shù)據(jù)長度是=4001
子進(jìn)程再次讀入的數(shù)據(jù)長度是=0

規(guī)則分析4

switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        char message[40001];
        int num = read(fd[0], message, 4001);
        printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d", num);
        num = read(fd[0], message, 4000);
        printf("子進(jìn)程再次讀入的數(shù)據(jù)長度是=%d", num);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[0]);
        const long int writesize = 4000;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize; i++) {
            writeMsg[i] = 'a';
        }
        int writenum = write(fd[1], writeMsg, strlen(writeMsg));
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[1]);
        break;
    }

[root@ Release29$] ps -C processcomm -o pid,ppid,stat,cmd
PID PPID STAT CMD
7916 1 S /root/workspace/processcomm/Release/processcomm
=>讀進(jìn)程阻塞

控制臺輸出:
父進(jìn)程工作 PID=7914,PPID=2488
父進(jìn)程寫入的數(shù)據(jù)長度是=4001
子進(jìn)程工作 PID=7916,PPID=1

規(guī)則分析5

switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
            close(fd[1]);
        char message[65535];
        int num = read(fd[0], message, 65535);
        printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d", num);
    close(fd[0]);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[0]);
        const long int writesize = 80000;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize; i++) {
            writeMsg[i] = 'a';
        }
        int writenum = write(fd[1], writeMsg, strlen(writeMsg));
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[1]);
        wait(NULL);
        break;
    }

[root@ Release25$] ps -C processcomm -o pid,ppid,stat,cmd
PID PPID STAT CMD
=>所有進(jìn)程都以退出

控制臺輸出
父進(jìn)程工作 PID=7776,PPID=2488
子進(jìn)程工作 PID=7778,PPID=7776
子進(jìn)程讀入的數(shù)據(jù)長度是=65535

規(guī)則分析6

switch (cid) { case -1: perror("子進(jìn)程創(chuàng)建失敗"); exit(2); break; case 0: printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid()); break; default: printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid()); const long int writesize=80000; char writeMsg[writesize]; int i; for(i=0;i<writesize;i++) { writeMsg[i]='a'; } int writenum=write(fd[1], writeMsg, strlen(writeMsg)); printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum); wait(NULL); break; } 父進(jìn)程工作 PID=7309,PPID=2488
子進(jìn)程工作 PID=7314,PPID=7309

[root@ Release24$] ps -C processcomm -o pid,ppid,stat,cmd
PID PPID STAT CMD
7309 2488 S /root/workspace/processcomm/Release/processcomm
7314 7309 Z [processcomm]

管道代碼舉例

1. 當(dāng)發(fā)送信息小于管道最大長度

#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
int main() {
    int fd[2];
    pid_t cid;
    if (pipe(fd) == -1) {
        perror("管道創(chuàng)建失敗!");
        exit(1);
    }
    cid = fork();
    switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[1]);
        char message[1000];
        int num;
        do {
            num = read(fd[0], message, 1000);
            printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d\n", num);
        } while (num != 0);
        close(fd[0]);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[0]);
        const long int writesize = 37;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize-1; i++) {
            writeMsg[i] = 'a';
        }
        writeMsg[writesize-1]='\0';
        int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[1]);
        break;
    }
    return 0;
}

2. 當(dāng)發(fā)送信息大于管道最大長度

此例子主要應(yīng)該規(guī)則6,當(dāng)發(fā)送信息大于管道長度時且寫進(jìn)程在未全部將新數(shù)據(jù)寫入管道中,寫進(jìn)程處于阻塞狀態(tài),直到所有數(shù)據(jù)寫入管道

int main() {
    int fd[2];
    pid_t cid;
    if (pipe(fd) == -1) {
        perror("管道創(chuàng)建失?。?);
        exit(1);
    }
    cid = fork();
    switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[1]);
        char message[1000];
        int num;
        do {
            num = read(fd[0], message, 1000);
            printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d\n", num);
        }while(num!=0);
        close(fd[0]);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        const long int writesize = 80000;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize-1; i++) {
            writeMsg[i] = 'a';
        }
        writeMsg[writesize-1]='\0';
        int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[0]);
        close(fd[1]);
        break;
    }
    return 0;
}

3. 寫進(jìn)程多次寫入

此例應(yīng)用規(guī)則6,防止多次寫入,寫入數(shù)據(jù)長度管道最大長度

int main() {
    int fd[2];
    pid_t cid;
    if (pipe(fd) == -1) {
        perror("管道創(chuàng)建失??!");
        exit(1);
    }
    cid = fork();
    switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[1]);
        char message[1000];
        int num;
        do {
            num = read(fd[0], message, 1000);
            if (num > 0) {
                printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d %s\n", num, message);
            }
        } while (num != 0);
        close(fd[0]);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        const long int writesize = 10;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize - 1; i++) {
            writeMsg[i] = 'a';
        }
        writeMsg[writesize - 1] = '\0';
        int writenum = write(fd[1], writeMsg, strlen(writeMsg));
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        char *newmsg = "helloworld";
        writenum = write(fd[1], newmsg, strlen(newmsg) + 1);
        printf("父進(jìn)程再次寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[0]);
        close(fd[1]);
        break;
    }
    return 0;
}

4. 兄弟間的管道通訊

int main() {
    int fd[2];
    pid_t cid, did;
    if (pipe(fd) == -1) {
        perror("管道創(chuàng)建失??!");
        exit(1);
    }
    cid = fork();
    switch (cid) {
    case -1:
        perror("兄進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("兄進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[1]);
        char message[1000];
        int num;
        do {
            num = read(fd[0], message, 1000);
            if (num > 0) {
                printf("兄進(jìn)程讀入的數(shù)據(jù)長度是=%d,%s\n", num, message);
            }
        } while (num != 0);
        close(fd[0]);
        break;
    default:
        did = fork();
        if (did == 0) {
            printf("弟進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
            const long int writesize = 10;
            char writeMsgs[writesize];
            int i;
            for (i = 0; i < writesize - 1; i++) {
                writeMsgs[i] = 'a';
            }
            writeMsgs[writesize - 1] = '\0';
            int writenum = write(fd[1], writeMsgs, strlen(writeMsgs) + 1);
            printf("弟進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
            close(fd[0]);
            close(fd[1]);
        } else if (did == -1) {
            perror("弟進(jìn)程創(chuàng)建失敗!");
            exit(3);
        }
        break;
    }
    return 0;
}

5. 父子雙通道管道通訊

int main() {
    int fd[2], backfd[2];
    pid_t cid;
    if (pipe(fd) == -1) {
        perror("管道創(chuàng)建失敗!");
        exit(1);
    }
    if (pipe(backfd) == -1) {
        perror("管道創(chuàng)建失敗!");
        exit(2);
    }
    cid = fork();
    switch (cid) {
    case -1:
        perror("子進(jìn)程創(chuàng)建失敗");
        exit(2);
        break;
    case 0:
        printf("子進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        close(fd[1]);
        char message[10000];
        int num;
        do {
            num = read(fd[0], message, 10000);
            printf("子進(jìn)程讀入的數(shù)據(jù)長度是=%d\n", num);
        } while (num != 0);
        close(fd[0]);
        close(backfd[0]);
        char *msg1 = "消息返回成功啊!";
        write(backfd[1], msg1, strlen(msg1) + 1);
        close(backfd[1]);
        break;
    default:
        printf("父進(jìn)程工作 PID=%d,PPID=%d\n", getpid(), getppid());
        const long int writesize = 80000;
        char writeMsg[writesize];
        int i;
        for (i = 0; i < writesize - 1; i++) {
            writeMsg[i] = 'a';
        }
        writeMsg[writesize - 1] = '\0';
        int writenum = write(fd[1], writeMsg, strlen(writeMsg) + 1);
        printf("父進(jìn)程寫入的數(shù)據(jù)長度是=%d\n", writenum);
        close(fd[0]);
        close(fd[1]);
        close(backfd[1]);
        char msg2[1000];
        int num1 = read(backfd[0], msg2, 1000);
        printf("返回消息是:%s", msg2);
        close(backfd[0]);
        break;
    }
    return 0;
}