进程间通信1——管道

进程间通信的作用是为了进行同步和交换数据。

一、管道

管道是进程之间的一个单向数据流。

1.1 什么是管道

把一个进程连接到另一个进程的一个数据流称为一个“管道”,通常是用作把一个进程的输出通过管道连接到另一个进程的输入。管道本质上是内核的一块缓存。一个进程在管道的尾部写入数据,另一个进程从管道的头部读出数据。管道包括无名管道和有名管道两种,前者只能用于父进程和子进程间的通信,后者可用于运行于同一系统中的任意两个进程间的通信。

1.2 管道的特点

  • 1、管道通讯是单向的,先进先出,有固定的读端和写端。
  • 2、数据被进程从管道读出后,在管道中该数据就不存在了。
  • 3、当进程去读取空管道的时候,进程会阻塞。
  • 4、当进程往满管道写数据时,进程会阻塞。
  • 5、管道容量为64KB(#define PIPE_BUFFERS 16 include/linux/pipe_fs_i.h)
    管道的小例子
    在这里插入图片描述

1.3 匿名管道(pipe)

概念
   匿名管道是基于文件描述符的通信方式。实现两个进程间的通信时必须通过fork创建子进程,实现父子进程之间的通信。

读写规则

  • 1、管道内没有数据时,读端(read)发生阻塞,等待有效数据进行读取
  • 2、管道容量被数据填满时,写端(write)发生阻塞,等待进程将数据读走再进行写入
  • 3、如果所有管道写端对应的文件描述符被关闭,read返回0,但会将之前管道里的数据读完
  • 4、如果所有管道的读端对应的文件描述符被关闭,write操作会产生信号,SIGPIPE,进而导致write进程退出
  • 5、当要写入的数据量不大于管道的容量(PIPE_BUF)时,linux将保证写入的原子性
  • 6、当要写入的数据量大于管道容量(PIPE_BUF)时,linux将不再保证写入的原子性

特点

  • 1、只能够进行单向通信。
  • 2、只能够用于有血缘关系(父子,兄弟,爷孙)的进程之间,多常用于父子之间。
  • 3、管道内部自带同步机制:子进程写一条,父进程读一条。
  • 4、管道在进行通信的时候,对外层提供的服务叫做面向字节流的服务
  • 5、当进程退出之时,管道也随之释放,与文件保持一致
  • 6、管道的生命周期为随进程,进程结束管道就没了

流:相当于水流,写入数据时,写多少字节和你自己有关系,读的时候没有 格式的要求,完全取决你自己;
字节流:以字节来读取和写入,字节数的大小完全取决于自己
单进程通信原理
在这里插入图片描述

父子进程通信原理
在这里插入图片描述

单进程通信实例

代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    int fd[2];//文件描述符数组
    char buf[1024];//临时缓冲区
    int len;
    ssize_t s;
    ssize_t w;
    if(pipe(fd) == -1)//创建管道
        {
         perror("pipe");
         return -1;
    }
        while(1)
        {
                printf("Please enter:");
                fflush(stdout);
                s = read(0,buf,sizeof(buf));//从屏幕上读取内容
                if( s < 0)
                {
                        perror("read");
                        return -2;
                }
                len = strlen(buf);
                w = write(fd[1],buf,len);//将读取的数据写入管道
                if(w != len)
                {
                        perror("write");
                        return -3;
                }
                memset(buf,0,sizeof(buf));//将buf清0
                s = read(fd[0],buf,sizeof(buf));//从管道当中读取数据
                if(s < 0)
                {
                        perror("read");
                        return -4;
                }
                w = write(1,buf,len);//将读的数据写入屏幕
                if(w != len)
                {
                        perror("write");
                        return -5;
                }
        }
    return 0;
}

结果:

在这里插入图片描述

1.4 命名管道(mkfifo)

概念

命名管道本质上是一个管道文件,可以通过命令创建也可以通过函数创建,用户可以看到。

特点

1. 可以进行不相干进程间的通信。
  2. 命名管道是一个文件,对于文件的相关操作对其同样适用。

读写规则

1. 对于管道文件,当前进程操作为只读时,则进行阻塞,直至有进程对其写入数据。
  2. 对于管道文件,当前进程操作为只写时,则进行阻塞,直至有进程从管道中读取数据。

扫描二维码关注公众号,回复: 10043552 查看本文章

示例代码:

write:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
//读取文件,将文件内容写入管道
int main()
{
     mkfifo("tp",0644);//创建一个管道文件
     int  infd = open("123",O_RDONLY);//打开一个文件
     if(infd == -1){
                 perror("open");
                  return 1;    
    }

     int outfd = open("tp",O_WRONLY);//打开管道文件,将123文件的内容写入管道文件
    if(outfd == -1){
                perror("open");
                 return 2;
    }

     char buf[1024];//用于存放文件内容
     ssize_t s;

     while( (s = read(infd,buf,sizeof(buf))) >0)
     {
                 write(outfd,buf,s);
     }
     close(infd);
     close(outfd);

}

Read

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//从管道文件里面读取内容,并将内容写入另一个文件中
int main()
{
       int infd = open("abc.bak",O_CREAT | O_WRONLY | O_TRUNC,0644);//创建一个新的文件
       if(infd == -1){
               perror("open");
               return 1;
       }

        //将从管道读取的内容写入到新的文件中

        int outfd = open("tp",O_RDONLY);//打开管道文件
        if(outfd == -1){
                perror("open");
                return 2;
        }

        char buf[1024];//临时数组
        ssize_t s;

        while( (s = read(outfd,buf,sizeof(buf))) > 0)
        {
            write(infd,buf,s);
        }
        close(infd);
        close(outfd);

        return 0;
}

5.总结

类型 进程关系 不同点 本质
匿名管道 必须是亲缘关系 由pipe创建并打开 内核的一块缓存
命名管道 两个毫不相干进程 由mkfifo创建,open打开 一个文件
发布了465 篇原创文章 · 获赞 694 · 访问量 96万+

猜你喜欢

转载自blog.csdn.net/mao_hui_fei/article/details/103785946