管道-無名管道

管道(pipe)概述:(怎樣使用管道實現父子進程間通信)不相關的兩個進程無法通過無名管道進行進程間通信。

管道又稱無名管道(沒有名字),無名管道是一種特殊類型的文件,在應用層體現爲兩個打開的文件描述符

管道是最古老的UNIX IPC方式,其特點是:

1>   半雙工,數據在同一時刻只能在一個方向上流動。(單工-收音機)

2>   數據只能從管道的一端寫入,從另一端讀出。

3>   寫入管道中的數據遵循先入先出的規則。

4>   管道所傳送的數據是無格式的,這要求管道的讀出方與寫入方必須事先約定好數據的格式,如多少字節算一個消息等。

5>   管道不是普通的文件,不屬於某個文件系統,只存在於內存中。

6>   管道在內存中對應一個緩衝區。不同的系統其大小不一定相同。

7>   從管道讀數據是一次性操作,數據一旦被讀走,它就從管道中被拋棄,釋放空間以便寫更多的數據。

8>   管道沒有名字,只能在具有公共祖先的進程之間使用。

Linuxshell允許重定向,而重定向使用的就是管道。例如:ls | more

創建管道的那個進程(父進程)具有管道的兩個文件描述符,繼承這個進程(子進程)也具有這兩個文件描述符,所以就可以對管道進行操作。父進程創建管道—>得到管道的兩個讀寫端->創建子進程,子進程繼承文件描述符(管道的兩個讀寫端)->父子進程進行進程間通信。

實際上,管道是一個固定大小的緩衝區,在linux中,該緩衝區的大小是4k(8×512Bytes),即一頁。


創建管道:

#include<unistd.h>

int pipe(int filedes[2]);

功能:經由參數filedes返回兩個文件描述符

參數:

>>filedes爲int型數組的首地址,其存放了管道的文件描述符filedes[0],filedes[1].

>>filedes[0]爲讀而打開,filedes[1]爲寫而打開管道,filedes[0]的輸出是filedes[1]的輸入。

返回值:成功返回0,失敗返回-1.


從管道中讀數據的特點:

1) 默認用read函數從管道中讀數據是阻塞的。

2) 調用write函數向管道里寫數據,當緩衝區已滿時write也會阻塞。

3) 通信過程中,讀端口全部關閉後,寫進程向管道內寫數據時,寫進程會(收到SIGPIPE信號)退出。

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

int main(int argc,char * argv[])
{
        int fd_pipe[2];
        char buf1[] = "hello world";
        char buf2[15];
        pid_t pid;
        if(pipe(fd_pipe) < 0)
                perror("pipe");
        pid = fork();
        if(pid < 0){
                perror("fork");
                exit(-1);
        }
        if(pid == 0){
                write(fd_pipe[1],buf1,strlen(buf1));
                _exit(0);
        }else{
                wait(NULL);//parent process,wait any child process's termination
                memset(buf2,0,sizeof(buf2));
                read(fd_pipe[0],buf2,sizeof(buf1));
                printf("buf2 = [%s]\n",buf2);
        }
        return 0;
}

運行結果:


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

int main(int argc,char * argv[])
{
        int fd_pipe[2];
        char buf[] = "hello world";
        pid_t pid;
        if(pipe(fd_pipe) < 0)
                perror("pipe");
        pid = fork();
        if(pid < 0){
                perror("fork");
                exit(-1);
        }
        if(pid == 0){
                int i = 0;
                close(fd_pipe[0]);
                while(1){
                        write(fd_pipe[1],buf,strlen(buf));
                        i++;
                        printf("i = %d\n",i);
                        sleep(1);
                }
                _exit(0);
        }else{
                int i;
                for(i = 0;i < 5;i++){
                        memset(buf,0,sizeof(buf));
                        read(fd_pipe[0],buf,sizeof(buf));
                        printf("read: buf = %s\n",buf);
                }
                close(fd_pipe[0]);
                wait(NULL);//parent process,wait any child process's termination
        }
        return 0;
}

父子進程都關閉讀端之後,寫端也將自動關閉,運行結果如下:


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