Linux進程間通信——管道通信

1. 進程間通信概述

進程間通信(Inter-Process Communication, IPC)是指在兩個或者多個不同得勁進程間傳遞或者交換信息,通過信息的傳遞建立幾個進程間的聯繫,協調一個系統中的多個進程之間的行爲。
1.1 進程間通信的工作原理
進程與進程之間是相互獨立的,各自運行在自己的虛擬內存中。要想在進程與進程間建立聯繫,需要通過內核,在內核中開闢一塊緩衝區,兩個進程的信息在緩衝區中進行交換或者傳遞。其原理如下圖所示。
在這裏插入圖片描述
進程間通信原理是:進程A中的數據寫入到內核中,進程B中的數據也寫入到內核中,兩者在內核中進行交換。交換後,進程A讀取內核中的數據,進程B也讀取內核中的數據,這樣兩個進程間交換數據的通信就完成了。兩個進程通過內核建立了聯繫,那麼交換數據、傳遞數據、發送事件等行爲就都可以實現了。
1.2 進程間通信的主要分類
在Linux系統中,常見的進程間通信主要包括管道通信、共享內存通信、信號量通信、消息隊列通信、套接口(SOCKET)通信和全雙工通信。
Linux系統除了支持信號和管道外,還支持SYSV(System V)子系統中的進程間通信機制。在SYSV的IPC機制中,包括共享內存、信號量、消息隊列通信。

2. 管道

管道與命名管道是最基本的IPC機制之一。管道主要用於父子或者兄弟進程間的數據讀寫,命名管道則可以在無關聯的進程間進行溝通傳遞數據。
2.1 管道的基本定義
所謂管道,就像生活中的煤氣管道、下水管道等傳輸氣體和液體的工具,而在進程通信意義上的管道就是傳輸信息或數據的工具。以下水管道爲例,當從管道一端輸送水流到另一端時,只有一個傳輸方向,不可能同時出現兩個傳輸方向。在Linux系統中的進程通信中,管道這個概念也是如此,某一時刻只能單一方向傳遞數據,不能雙向傳遞數據,這種工作模式就叫做半雙工模式。半雙工工作模式的管道通信是隻能從一端寫數據,從另一端讀數據。

2.2 管道創建和管道關閉
管道由Linux系統提供的pipe()函數創建,該函數原型爲:

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

pipe()函數用於在內核中創建一個管道,該管道一端用於讀取管道中的數據,另一端用於將數據寫入管道。在創建一個管道後,會獲得一對文件描述符,用於讀取和寫入,然後將參數數組filedes中的兩個值傳遞給獲取到的兩個文件描述符,filedes[0]指向管道的讀端,filedes[1]指向寫端。
pipe()函數調用成功,返回值爲0;否則返回-1,並且設置了適當的錯誤返回信息。此函數只是創建了管道,要想從管道中讀取數據或者向管道中寫入數據,需要使用read()和write()函數來完成。當管道通信結束後,需要使用close()函數關閉管道的讀寫端。

2.3 pipe()函數實現管道通信
(1)在父進程中調用pipe()函數創建一個管道,產生一個文件描述符filedes[0]指向管道的讀端和另一個文件描述符filedes[1]指向管道的寫端。
(2)在父進程中調用fork()函數創建一個一模一樣的新進程,也就是所謂的子進程。父進程的文件描述符一個指向讀端,一個指向寫端。子進程同理。
(3)在父進程關閉指向管道寫端的文件描述符filedes[1],在子進程中,關閉指向管道讀端的文件描述符filedes[0]。此時,就可以將子進程中的某個數據寫入到管道,然後在父進程中,將此數據讀出來。
過程如下圖所示:
在這裏插入圖片描述
其程序代碼如下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define MAXSIZE 100

int main()
{
    int fd[2], pid, line;
    char message[MAXSIZE];
    /*創建管道*/
    if(pipe(fd) == -1)
    {
	perror("create pipe failed!");
	return 1;
    }
    /*創建新進程*/
    else if((pid = vfork()) < 0)
    {
	perror("not create a new process!");
	return 1;
    }
    /*子進程*/
    else if(pid == 0)
    {
	close(fd[0]);
	printf("child process SEND message!\n");
	write(fd[1], "Hello Linux!",12); /*向文件中寫入數據*/ 
    }
    else
    {
	close(fd[1]);
	printf("parent process RECEIVE message is:\n");
	line = read(fd[0], message, MAXSIZE); /*讀取消息,返回消息長度*/
	write(STDOUT_FILENO,message,line); /*將消息寫入終端*/
	printf("\n");
	wait(NULL);
	_exit(0);
    }
    return 0;
}

結果:
在這裏插入圖片描述
管道特點:

  1. 只能用於具有共同祖先的進程(具有親緣關係的進程)之間進行通信;通常,一個管道由一個進程創建,然後該進程調用fork(),此後父子進程之間就可以應用該管道。
  2. 一般而言,進程退出,管道釋放,所以管道的生命週期跟隨進程。
  3. 一般而言,內核會對管道操作進行同步與互斥
  4. 管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道。
    在這裏插入圖片描述

3. 命名管道

以上介紹的管道通信的方法有很多限制。受限制之一就是兩個進程必須是相關聯的進程。若是沒有關係的進程間通信就要用命名管道。命名管道通常被稱爲FIFO。它作爲特殊的設備文件存在於文件系統中。因此,在進程中可以使用open()和close()函數打開和關閉命名管道。

3.1 創建一個命名管道
· 命名管道可以從命令行上創建,命令行方法是使用下面這個命令:

$ mkfifo filename

· 也可以從程序裏創建,相關函數:

#include <sys/tyoes.h>
#include <sys/stat.h>
int mkfifo(const char* pathname, mode_t mode);

該函數的參數pathname是一個文件的路徑名,是創建的一個命名管道的文件名;參數mode是指文件的權限,文件權限取決於(mode&~umask)的值。
使用mkfifo()函數創建的命名管道文件與前面介紹的管道通信相似,只是它們創建方式不同。訪問命名管道文件與訪問文件系統中的其他文件一樣,都是需要首先打開文件,然後對文件進行讀寫數據。如果在命名管道文件中讀取數據時,並沒有其他進程向命名管道文件中寫入數據,則會出現進程阻塞狀態;如果在寫入數據的同時,沒有進程從命名管道中讀取數據,也會出現進程阻塞狀態。
程序如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define FIFO "/root/process/hello"

int main()
{
    int fd;
    int pid;
    char r_msg[BUFSIZ];
    if((pid = mkfifo(FIFO,0777))==-1) /*創建命名管道*/
    {
	perror("create fifo channel failed!");
	return 1;
    }
    else
    printf("create success!\n");
    fd = open(FIFO, O_RDWR);  /*打開命名管道*/
    if(fd == -1)
    {
	perror("cannot open the FIFO");
	return 1;
    }
    if(write(fd,"hello world", 12) == -1)  /*寫入消息*/
    {
	perror("write data error!");
	return 1;
    }
    else
    printf("write data success!\n");
    if(read(fd, r_msg, BUFSIZ) == -1)  /*讀取消息*/
    {
	perror("read error!");
	return 1;
    }
    else
    printf("the receive data is:  %s\n",r_msg);
    close(fd);   /*關閉文件*/
    return 0;
}

在這裏插入圖片描述
通過以上代碼,可以瞭解到使用mkfifo()函數創建命名管道並進行數據傳遞的過程:
(1)用mkfifo()函數創建一個命名管道,命名管道文件路徑爲/root/process/hello
(2)調用open()函數打開該命名管道文件,以讀寫的方式打開。
(3)調用write()函數向文件寫入信息"hello world", 同時調用read()函數讀取該文件,輸出到終端。
(4)調用close()函數關閉打開的命名管道文件。

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