進程間通信(管道和有名管道)


管道(Pipe)是兩個進程之間進行單向通信的機制,因為它的單向性,所以又稱為半雙工管道。它主要用於進程間的一些簡單通信。

  1. 數據只能由一個進程流向另一個進程(一個寫管道,一個讀管道);如果要進行全雙工通信,需要建立兩個管道。
  2. 管道只能用於父子進程或者兄弟進程之間的通信。
  3. 管道沒有名字,且其緩沖區大小有限。
  4. 一個進程向管道寫數據,數據每次都添加在管道緩沖區的末尾;另一個進程從管道另一端讀數據,從緩沖區頭部讀出數據。

創建管道的命令:

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

管道兩端分別用描述符fd[0]和fd[1]來描述。其中fd[0]只能用於讀,稱為管道讀端;fd[1]只能用於寫,稱為管道寫端。
管道的一般用法:先創建一個管道,之后用fork創建一個子進程,之后父進程關閉管道的讀端(或寫端),子進程關閉管道的寫端(或讀端),父進程向管道寫輸入,子進程就能從管道讀數據了。

例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
 
/*讀管道*/
void read_from_pipe (int fd)
{
        char message[100];
        read (fd,message,100);
        printf("read from pipe:%s",message);
}
 
/*寫管道*/
void write_to_pipe (int fd)
{
        char *message = "Hello, pipe!\n";
        write (fd, message,strlen(message)+1);
}
 
int main(void)
{
        int     fd[2];
        pid_t   pid;
        int     stat_val;
 
        if (pipe (fd))
        {
                printf ("create pipe failed!\n");
                exit (1);
        }
 
        pid = fork();
        switch (pid)
        {
                case -1:
                        printf ("fork error!\n");
                        exit (1);
                case 0:
                        /*子進程關閉fd1*/
                        close (fd[1]);
                        read_from_pipe (fd[0]);
                        exit (0);
                default:
                        /*父進程關閉fd0*/
                        close (fd[0]);
                        write_to_pipe (fd[1]);
                        wait (&stat_val);
                        exit (0);
        }
 
        return 0;
}

 

有名管道

管道的一個不足之處是沒有名字,因此只能在具有親緣關系的進程之間通信。而“有名管道”與此不同,它提供了一個路徑名與之關聯,作為一個設備文件存在,即使無親緣關系的進程之間,只要能訪問該路徑,也可以通過FIFO進行通信。FIFO總是按照先進先出的原則工作,第一個被寫入的數據將首先從管道中讀出。

函數原型:

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

path為創建有名管道的路徑名;mode為創建有名管道的模式,指明其存取權限。函數調用成功返回0,失敗返回-1。
      使用一個存在的有名管道之前,需要用open()將其打開。因為有名管道是一個存在於硬盤上的文件,而管道是存在於內存中的特殊文件。

      以下程序演示有名管道在無親緣關系的進程之間如何通信。

寫端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#define FIFO_NAME    "myfifo"
#define BUF_SIZE    1024
 
int main(void)
{
    int     fd;
    char    buf[BUF_SIZE] = "Hello procwrite, I come from process named procread!";
 
    umask(0);
    //指明創建一個有名管道且存取權限為0666,即創建者、與創建者同組的用戶、其他用戶對該有名管道的訪問權限都是可讀可寫
    if (mkfifo (FIFO_NAME, S_IFIFO | 0666) == -1)        
    {
        perror ("mkfifo error!");
        exit (1);
    }
 
    if((fd = open (FIFO_NAME, O_WRONLY) ) == -1)/*以寫方式打開FIFO*/
    {
        perror ("fopen error!");
        exit (1);
    }
    write (fd, buf, strlen(buf)+1); /*向FIFO寫數據*/
 
    close (fd);
    exit (0);

}

讀端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
 
#define FIFO_NAME      "myfifo"
#define BUF_SIZE        1024
 
int main(void)
{
        int     fd;
        char    buf[BUF_SIZE];
 
        umask (0);
        fd = open(FIFO_NAME, O_RDONLY);
        read (fd, buf, BUF_SIZE);
        printf ("Read content: %s\n", buf);
        close (fd);
        exit (0);
}

 

以上就是管道和有名管道的基本用法了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM