进程间通信(管道和有名管道)

管道(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);
}

 

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

posted @ 2019-07-28 22:02  还好一直有你  阅读(1422)  评论(0编辑  收藏  举报