Linux_進程間通信(管道)

進程間通信

進程間通信目的

數據傳輸:一個進程需要將他的數據發送給另一個進程

資源共享:多個進程間共享同樣的資源

通知時間:一個進程需要向另一個進程發送消息,通知他們發生了某種事件(如進程終止時要通知父進程)

進程控制:有些進程希望完全控制另一個程序的執行(如debug),此事控制進程希望能夠攔截另一個進程的所有陷入和異常,並能夠及時知道他的狀態改變

進程間通信發展

管道:

System V進程間通信

POSIX進程間通信

進程間通信分類:

1.匿名管道

2.命名管道

3.System V IPC:

System V 消息隊列

System V 共享內存

System V 信號量

4.POSIX IPC:

消息隊列

共享內存

信號量

互斥量

條件變量

讀寫鎖

管道

管道定義:

管道是最古老的進程間通信的方式

吧從一個進程連接到另一個進程的一個數據流稱爲一個“管道”


匿名管道

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

功能:創建一個匿名管道,參數:fd,文件描述符數組,其中fd【0】表示讀端,fd【1】表示寫端

返回值:成功返回0,失敗返回錯誤代碼


實例:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(){
    int fd[2];
    int ret = pipe(fd);
    if(ret < 0){
        perror("pipe");
        return 1;
    }

    pid_t id = fork();
    if(id == 0){//child//子進程寫,父進程讀
        close(fd[0]);
        int count = 0;
        const char *msg = "hello f,I am c!\n";
        while(1){
            usleep(1000);
            write(fd[1],msg,strlen(msg));
            printf("%d\n",count++);
        }
    }else{//father
        close(fd[1]);
        char buf[64];
        while(1){
            ssize_t s = read(fd[0],buf,sizeof(buf)-1);
            if(s > 0){
                buf[s] = '\0';
                printf("f say: %s\n",buf);
            }
        }
    

//    printf("%d,%d\n",fd[0],fd[1]);
    return 0;
}

用fork共享管道的原理


深度理解管道

1.父進程創建管道


2.父進程fork出子進程


3.父進程關閉fd[0],子進程關閉fd[1]


所以實質上,看待管道,就如同看待文件一樣!管道使用方法和文件是一樣的,符合Linux下一切皆文件的思想。

那麼當我們的子進程寫的快,父進程讀的很慢或者父進程讀的很快,子進程寫的很慢的時候,會怎麼樣呢》接下來要提到管道讀寫規則:

當沒有數據可讀時:

    O_NONBLOCK disable:read調用阻塞,即進程暫停執行,一直等到有數據來爲止。

    O_NONBLOCK enable:read調用返回-1,errno值爲EAGAIN。

當管道滿的時候:

    O_NONBLOCK disable:write調用阻塞,直到有進程讀走數據

    O_NONBLOCK enable:write調用返回-1,errno值爲EAGAIN。

如果所有的管道寫端對應的文件描述符被關閉,則read返回0

如果所有的管道讀端對應的文件描述符被關閉,則write操作會產生信號SIGPIPE,進而可能導致write進程退出

當要寫入的數據量不大於PIPE_BUF時,linux將保證寫入的原子性

當要寫入的數據量不大於PIPE_BUF時,linux將不再保證寫入的原子性

管道特點:

    只能用於具有共同祖先的進程(具有親緣關係的進程)之間進行通信;通常,一個管道由一個進程創建,然後該進程調用fork,此後父子進程之間就可應用該管道。

    管道提供流式服務

    一般而言,進程退出,管道釋放,所以管道的生命週期隨進程

    一般而言,內核會對管道操作進行同步與互斥

    管道是半雙工的,數據智能向一個方向流動;需要雙方通信時,需要建立兩個管道。

命名管道

    管道應用的一個限制就是只能在具有相同祖先(具有親緣關係)的進程間通信。

    如果我們想在不相關的進程之間交換數據,可以使用fifo文件來做這項工作,他經常被稱爲命名管道。

    命名管道是一種特殊類型的文件

命名管道創建

    命令行方式:mkfifo filename

    程序創建:int mkfifo(const char* filename,mode_t mode)

匿名管道與命名管道的區別

    匿名管道由pipe函數創建並打開

    命名管道由mkfifo函數創建,打開用open

    FIFO(命名管道)與pipe(匿名管道)之間唯一的區別在於他們創建和打開的方式不同,一旦這些工作完成之後,他們具有相同的語義。

命名管道的打開規則

如果當前打開操作是爲讀而打開FIFO時

    O_NONBLOCK disable:阻塞到直到有相應進程爲寫而打開該FIFO

    O_NONBLOCK enable:立刻返回成功

如果當前打開操作是爲寫而打開FIFO時

    O_NONBLOCK disable:阻塞到直到有相應進程爲讀而打開該FIFO

    O_NONBLOCK endble:立刻返回失敗,錯誤碼爲ENXIO

例:client/server

server:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>


int main(){
    umask(0);
    if(mkfifo("mypipe",0644)<0){
        perror("fifo error\n");
        return 1;
    }

    int rfd = open("mypipe",O_RDONLY);
    if(rfd < 0){
        perror("rfd error\n");
        return -1;
    }

    char buf[1024];
    while(1){
        buf[0] = 0;
        printf("please waite....\n");
        ssize_t s = read(rfd,buf,sizeof(buf)-1);
        if(s>0){
            buf[s] = '\0';
            printf("Client say# %s\n",buf);
        }else if(s == 0){
            printf("Client quit,exit now!\n");
            exit(EXIT_SUCCESS);
        }else
            exit(EXIT_FAILURE);
    }
    close(rfd);
    return 0;
}

client:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

int main(){
    int wfd = open("mypipe",O_WRONLY);
    if(wfd < 0){
        perror("wfd error\n");
        return 1;
    }

    char buf[1024];
    while(1){
        buf[0] = 0;
        printf("Please Enter# ");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf)-1);
        if(s > 0){
            buf[s] = 0;
            write(wfd,buf,strlen(buf));
        }else{
            perror("error");
            return -1;
        }
    }
    close(wfd);
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章