溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

IPC之管道

發(fā)布時間:2020-08-11 18:19:40 來源:網絡 閱讀:1212 作者:SherryX 欄目:系統運維

現在linux使用的IPC(Inter-Process Communication,進程間通信)方式有以下幾種:
-(1)管道(pipe)和匿名管道(FIFO)
-(2)信號(signal)
-(3)消息隊列
-(4)共享內存
-(5)信號量
-(6)套接字(socket)

什么是管道

管道是Unix中最古老的進程間通信的形式。我們把一個進程連接到另一個進程的一個數據流成為一個“管道”。

  • 管道是半雙工的,數據只能向一個方向流動;需要雙方通信的時候,需要建立其兩個管道。
  • 只能用于父子進程或者兄弟進程之間(具有親緣關系的進程)進行通信。

    pipe函數

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

    功能:創(chuàng)建無名管道
    參數:文件描述符組。fd[0]表示讀端,fd[1]表示寫端。
    返回值:成功返回0,失敗返回錯誤代碼

    也就是說,在fork()之前pipe(),就可以使得父子進程之間建立起一個管道,畫個圖:
    IPC之管道
    父子進程都會打開5個文件描述符,除了默認的0、1、2。還有fd[0]、fd[1]。測試一下,就會知道這兩個文件描述符為3、4。
    寫串代碼用一用:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    int main()
    {
    int fd[2];
    int retByte;
    pid_t pid;
    char buf[20] = "";
    
    pipe(fd);   /*創(chuàng)建無名管道*/
    //printf("%d,%d\n",fd[0],fd[1]);
    
    pid = fork();
    if(pid == -1)
    {
        perror("create fork");
        return -1;
    }
    if(pid == 0)
    {
        //子進程,寫端,使用fd[1]
        //close(fd[0]);
        //close(fd[1]);
        while(1)
        {
            scanf("%s",buf);
            if( write(fd[1],buf,strlen(buf)) == -1)
            {
                perror("write");
                return -1;
            }
            memset(buf,0,20);
            if(read(fd[0],buf,5) > 0 )
            {
                printf("child-read msg: %s\n",buf);
            }
        }
    }
    else
    {
        //父進程,讀端,使用fd[0]
        while(1)
        {
            memset(buf,0,20);
            retByte = read(fd[0],buf,5);//每次只讀5個
            if( retByte == -1)  
            {
                perror("read");
                return -1;
            }
            if(retByte > 0)
            {
                printf("parent-read msg: %s\n",buf);
            }
        }
    }
    return 0;
    }

    運行結果:
    IPC之管道
    那么,如果沒有讀端呢?也就是父子進程的fd[0]都關閉了,會有什么現象呢?

    void handler(int no)
    {
        printf("SIGPIPE.\n");
    }
    
    int main()
    {
            int fd[2];
            int retByte;
            int rlt;
            pid_t pid;
            char buf[20] = "";
    
            rlt = pipe(fd); /*創(chuàng)建無名管道*/
            //printf("%d,%d\n",fd[0],fd[1]);
    
            signal(SIGPIPE,handler);
    
            if(rlt != 0)
            {
                perror("pipe");
                return -1;
            }
    
            pid = fork();
            if(pid == -1)
            {
                perror("create fork");
                return -1;
            }
            if(pid == 0)
            {
                //子進程,寫端,使用fd[1]
                close(fd[0]);
                //close(fd[1]);
                while(1)
                {
                    scanf("%s",buf);
                    if( write(fd[1],buf,strlen(buf)) == -1)
                    {
                        perror("write");
                        return -1;
                    }
                    memset(buf,0,20);
                }
            }
            else
            {
                //父進程,讀端,使用fd[0]
                close(fd[0]);
                while(1)
                {
                }
            }
            return 0;
    }

    運行結果:
    IPC之管道
    會出現管道破裂!!(如果沒有重寫管道破裂的處理函數,系統默認的處理方式就是殺死進程,父子進程都over了)

    管道讀寫規(guī)則

    所以,總結一下讀寫規(guī)則:
    讀規(guī)則:
    1)緩沖區(qū)沒數據:阻塞
    2)緩沖區(qū)的數據少于請求字節(jié)數:緩沖區(qū)有多少就讀多少
    3)緩沖區(qū)的數據多于請求字節(jié)數:只讀取請求字節(jié)數,剩下的還在緩沖區(qū)
    4)寫端關閉:讀端等待。
    寫規(guī)則:
    1)緩沖區(qū)滿了:寫不進去
    2)沒有讀端:管道破裂,父子進程都結束了。調試到write,發(fā)生SIGPIPE。
    注意:讀端和寫端的對應關系可以是一對一、一對多、多對一、多對多的。

    練習

    上面講到,緩沖區(qū)如果滿了,就寫不進去了。那么緩沖區(qū)有多大呢?換言之,如何檢測linux中管道的容量?
    代碼如下:

    int main()
    {
    int fd[2];
    pipe(fd);
    char buf[4096]; //4k
    int i,loop,ret;
    
    for(i = 0 ; i < sizeof(buf) ; i++)
    {
        buf[i] = 'a';
    }
    
    loop = 100 ; //如果循環(huán)結束,還沒阻塞,增加循環(huán)次數
    for(i = 0; i < loop ; i++)
    {
        ret = write(fd[1],buf,sizeof(buf));
        if(ret == -1)
        {
            perror("write error!\n");
            return 1;
        }
        else
        {
            printf("write successfully!    ");
            printf("size: %d K\n", (i+1)*4);
        }
    }
    
    close(fd[0]);
    close(fd[1]);
    
    return 0;
    }

    運行結果:
    IPC之管道
    在寫完64k的時候出現阻塞,說明管道已經滿了。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI