Linux进程间的通信方法之管道

目录

1.进程间通信的方法

2.管道的分类

3.有名管道

3.1常用命令

3.2 有名管道来演示进程间通信

4 无名管道

5 管道的特点

6 管道的实现


1.进程间通信(IPC)的方法

(1)管道

(2)信号量

(3)共享内存

(4)消息队列

(5)套接字

2.管道的分类

有名管道和无名管道

区别:有名管道在任意两个进程之间通信,无名管道在父子进程之间通信。

3.有名管道

有名管道也称为命名管道

3.1常用命令

  • 创建有名管道使用命令:mkfifo
  • 打开管道:open();
  • 关闭管道:close();
  • 读数据:read();
  • 写入数据:write();

3.2 有名管道来演示进程间通信

思考1:如果进程a要从键盘获取数据传递给另一个进程b,用已具备的知识思考

使用文件即可

问题:1很慢  2.读数据时不知道a什么时候会写入。

管道创建之后,它会在内存上分配一块空间,所以,管道的大小永远为0(大小指在磁盘上占据的空间)

例:管道一个是读打开,一个是写打开。

代码如下:

//a.c
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int fd=open("fifo",O_WRONLY);
    assert(fd!=-1);

    printf("fd=%d\n",fd);
    write(fd,"hello",5);
    close(fd);
}

//b.c
#include 
#include 
#include 
#include 
#include 

int main()
{
    int fd=open("fifo",O_RDONLY);
    assert(fd!=-1);

    printf("fd=%d\n",fd);

    char buff[128]={0};
    read(fd,buff,127);
    printf("read:%s\n",buff);
    close(fd);
    exit(0);
}

思考:a循环写入(从键盘写入),b循环读取,如何实现?

代码如下:

//a.c
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int fd=open("fifo",O_WRONLY);
    assert(fd!=-1);

    printf("fd=%d\n",fd);
    while(1)
    {   
        printf("input:\n");
        char buff[128]={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        write(fd,buff,strlen(buff));
    }   
  
    close(fd);
}

//b.c
#include 
#include 
#include 
#include 
#include 

int main()
{
    int fd=open("fifo",O_RDONLY);
    assert(fd!=-1);

    printf("fd=%d\n",fd);
    while(1)
    {   
        char buff[128]={0};
        if(read(fd,buff,127)==0)//管道写端关闭,读read返回值为0
        {
            break;
        }
        printf("read:%s\n",buff);
    }   

    close(fd);
    exit(0);
}

Linux进程间的通信方法之管道_第1张图片

4 无名管道

父子进程间通信

1.创建无名管道的命令:pipe

int pipe(int pipefd[2]);//提示数组里面有两个成员,有没有2其实没有实际含义,以下两种书写方式也可:

int pipe(int pipefd[]);

int pipe(int* pipefd);

调用pipe系统调用之后,返回两个文件描述符,fd[0]为读端,fd[1]为写端;

代码:

#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int fd[2];
    assert(pipe(fd)!=-1);
    //fd[0] 读端  fd[1]写端

    pid_t pid=fork();
    assert(pid!=-1);

    if(pid==0)
    {   
        close(fd[1]);//关闭写端,因为fork之后有两对读写端,不关闭的话,read的返回
值不为0
        char buff[128]={0};//开始读数据
        read(fd[0],buff,127);
        printf("child read:%s\n",buff);
        close(fd[0]);//关闭读端
    }
    else//在父端进行写操作,关闭读端
    {
        close(fd[0]);
        write(fd[1],"hello",5);
        close(fd[1]);
    }
    exit(0);
}
     

5 管道的特点

(1)管道必须读,写进程同时open,否则会阻塞;

(2)如果管道没有数据,那么read会阻塞;

(3)管道的写端关闭,读read返回值为0;

(4)管道打开的时候只有只读和只写两种方式,读写方式打开是未定义的。

(5)无论有名还是无名,写入管道的数据都在内存中(管道的大小永远为0,面试的重点)

(6)管道是一种半双工通信方式(通信方式有单工,半双工,全双工

(7)有名管道和无名管道的区别:有名管道可以在任意进程间使用,无名管道主要在父子进程间通信。

(8)管道的写端关闭,写会产生异常(发送SIGPIPE),SIGPIPE为读端关闭的描述符,写端写入时产生,该信号会终止程序(向无读进程的管道写数据)

6 管道的实现

Linux进程间的通信方法之管道_第2张图片

管道的结构是一个循环队列,从头指针端写入数据(头指针指向待写入的位置),从尾指针端读。

如果管道是空的,读操作会阻塞;如果管道是满的,写操作会阻塞。 

你可能感兴趣的:(Linux,linux)