Linux管道(匿名PIPE),linux管道匿名pipe

來源:互聯網
上載者:User

Linux管道(匿名PIPE),linux管道匿名pipe
管道基本概念

    管道是Unix中最古老的處理序間通訊的形式。

    我們把從一個進程串連到另一個進程的一個資料流稱為一個“管道”

      如:ps aux | grep httpd | awk '{print $2}'

 

管道



管道的本質

    固定大小的核心緩衝區

管道限制

    1)管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;

    2)匿名管道只能用於具有共同祖先的進程(如父進程與fork出的子進程)之間進行通訊;[通常,一個管道由一個進程建立,然後該進程調用fork,此後父子進程共用該管道]

 

匿名管道pipe

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

 

功能

    建立無名管道

參數

   Pipefd:檔案描述符數組,其中pipefd[0]表示讀端,pipefd[1]表示寫端

 

管道建立

//自己實現管道void err_exit(string str);int main(){    int pipefd[2];    if (pipe(pipefd) == -1)        err_exit("pipe error");    pid_t pid;    if ((pid = fork()) < 0)        err_exit("fork error");    if (pid == 0)   //In Child, Write pipe    {        close(pipefd[0]);        //使得STDOUT_FILENO也指向pipefd[1],亦即ls命令的輸出將列印到管道中        dup2(pipefd[1],STDOUT_FILENO);        //此時可以關閉管道寫端        close(pipefd[1]);        execlp("/bin/ls","/bin/ls",NULL);        //如果進程映像替換失敗,則列印下面出錯資訊        fprintf(stderr,"Child: execlp error");        exit(0);    }    //In Parent    close(pipefd[1]);    //使得STDIN_FILENO也指向pipefd[2],亦即wc命令將從管道中讀取輸入    dup2(pipefd[0],STDIN_FILENO);    //此時可以關閉管道讀端    close(pipefd[0]);    execlp("/usr/bin/wc","/usr/bin/wc","-w",NULL);    //如果進程映像替換失敗,則列印下面出錯資訊    fprintf(stderr,"Parent: execlp error");    return 0;}void err_exit(string str){    perror(str.c_str());    exit(EXIT_FAILURE);}

樣本:管道編程實踐

void err_exit(string str);int main(){    int pipefd[2];    int ret;    if ((ret = pipe(pipefd)) != 0)    {        err_exit("pipe error");    }    pid_t pid = fork();    if (pid == -1)    {        err_exit("fork error");    }    if (pid == 0)   //In Child, Write pipe    {        close(pipefd[0]);   //Close Read pipe        string str("I Can Write Pipe from Child!");        write(pipefd[1],str.c_str(),str.size());    //Write to pipe        close(pipefd[1]);        exit(0);    }    //In Parent, Read pipe    close(pipefd[1]);   //Close Write pipe    char buf[1024];    memset(buf,0,sizeof(buf));    read(pipefd[0],buf,sizeof(buf));    //Read from pipe    cout << "Read from pipe: " << buf << endl;    close(pipefd[0]);    return 0;}void err_exit(string str){    perror(str.c_str());    exit(EXIT_FAILURE);}

匿名管道讀寫規則

1)管道空時

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

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

 

2)管道滿時

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

    O_NONBLOCK enable:調用返回-1,errno值為EAGAIN

 

3)管道不停被寫,寫滿

    O_NONBLOCK disable: write調用阻塞(Block)

    O_NONBLOCK enable:調用返回-1,errno值為EAGAIN

//樣本:設定父進程Unblock讀PIPEint main(){    int pipefd[2];    int ret;    if ((ret = pipe(pipefd)) != 0)    {        err_exit("pipe error");    }    pid_t pid = fork();    if (pid == -1)    {        err_exit("fork error");    }    if (pid == 0)   //In Child, Write pipe    {        sleep(10);        close(pipefd[0]);   //Close Read pipe        string str("I Can Write Pipe from Child!");        write(pipefd[1],str.c_str(),str.size());    //Write to pipe        close(pipefd[1]);        exit(0);    }    //In Parent, Read pipe    close(pipefd[1]);   //Close Write pipe    char buf[1024];    memset(buf,0,sizeof(buf));    //Set Read pipefd UnBlock!    int flags = fcntl(pipefd[0],F_GETFL);    flags |= O_NONBLOCK;    ret = fcntl(pipefd[0],F_SETFL,flags);    if (ret != 0)    {        err_exit("Set UnBlock error");    }    int readCount = read(pipefd[0],buf,sizeof(buf));    //Read from pipe    if (readCount < 0)    {        //read立刻返回,不再等待子進程發送資料        err_exit("read error");    }    cout << "Read from pipe: " << buf << endl;    close(pipefd[0]);    return 0;}

 

4)如果所有管道寫端對應的檔案描述符被關閉,則read返回0

int main(){    int pipefd[2];    int ret;    if ((ret = pipe(pipefd)) != 0)    {        err_exit("pipe error");    }    pid_t pid = fork();    if (pid == -1)    {        err_exit("fork error");    }    if (pid == 0)   //In Child    {        //close all        close(pipefd[0]);        close(pipefd[1]);        exit(0);    }    //In Parent    sleep(1);    close(pipefd[1]);   //Close Write pipe, Now all pipefd[1] Closed!!!    char buf[1024];    memset(buf,0,sizeof(buf));    int readCount = read(pipefd[0],buf,sizeof(buf));    //Read from pipe    if (readCount == 0)    {        cout << "OK, read 0 byte" << endl;    }    close(pipefd[0]);    return 0;}

 

5)如果所有管道讀端對應的檔案描述符被關閉,則write操作會產生訊號SIGPIPE

void onSignalAction(int signalNumber){    switch(signalNumber)    {    case SIGPIPE:        cout << "receive signal SIGPIPE: " << signalNumber << endl;        break;    default:        cout << "other signal" << endl;        break;    }}int main(){    if (signal(SIGPIPE,onSignalAction) != 0)    {        err_exit("signal error");    }    int pipefd[2];    int ret;    if ((ret = pipe(pipefd)) != 0)    {        err_exit("pipe error");    }    pid_t pid = fork();    if (pid == -1)    {        err_exit("fork error");    }    if (pid == 0)   //In Child, Write pipe    {        //Wait Parent Close pipefd[0]        sleep(1);        close(pipefd[0]);        string str("I Can Write Pipe from Child!");        write(pipefd[1],str.c_str(),str.size());    //Write to pipe        close(pipefd[1]);        exit(0);    }    //In Parent, Close All Pipe    close(pipefd[1]);    close(pipefd[0]);    wait(NULL);    return 0;}

Linux PIPE特徵

    1)當要寫入的資料量不大於PIPE_BUF時,Linux將保證寫入的原子性。

    2)當要寫入的資料量大於PIPE_BUF時,Linux將不再保證寫入的原子性。

 

//樣本:測試PIPE_BUF大小int main(){    int pipefd[2];    int ret = pipe(pipefd);    if (ret < 0)    {        err_exit("pipe error");    }    int flags = fcntl(pipefd[1],F_GETFL);    flags |= O_NONBLOCK;    ret = fcntl(pipefd[1],F_SETFL,flags);    if (ret < 0)    {        err_exit("fcntl error");    }    //Write test    unsigned int countForTestPipe = 0;    while (true)    {        ret = write(pipefd[1],"a",1);        if (ret < 0)        {            break;        }        ++ countForTestPipe;    }    cout << "size = " << countForTestPipe << endl;}/**測試結果:Ubuntu 14.04 X64  xiaofang@xiaofang-Lenovo-G470:~/apue/it$ ./main   size = 65536*/


附-管道容量查詢

    man 7 pipe

 

 

 

附-深入理解檔案描述符

int main(){    close(STDIN_FILENO);    if (open("readfile.txt",O_RDONLY) == -1)    {        err_exit("open read error");    }    close(STDOUT_FILENO);    if (open("writefile.txt",O_WRONLY|O_TRUNC|O_CREAT,0644) == -1)    {        err_exit("open write error");    }    if (execlp("/bin/cat","/bin/cat",NULL) == -1)    {        err_exit("execlp error");    }    return 0;}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.