有名管道实现进程间通信

  • Post author:
  • Post category:其他


在Linux中实现进程间通信:

实现描述:

进程A:

1. 判断有名管道fifo1与fifo2是否创建:

1.1 没创建,需要首先创建管道;

1.2. 创建好了:

1.2.1 进程A 以只写的方式打开管道1,只读的方式打开管道2

1.2.2 定义一个内核缓冲区

1.2.3 向管道1中,写入数据之前清空缓冲区

1.2.4 向缓冲区中写入数据

1.2.5 写完数据后等待进程B向管道2中发送数据以读取

1.2.6 打印读取的数据

进程B:

1. 判断有名管道fifo1与fifo2是否创建:

1.1 没创建,需要首先创建管道;

1.2. 创建好了:

1.2.1 进程B 以只读的方式打开管道1,只写的方式打开管道2

1.2.2 定义一个内核缓冲区

1.2.3 在管道1中,读取数据之前清空缓冲区

1.2.4 从缓冲区中读取数据

1.2.5 打印读取的数据

1.2.6 读完数据后向管道2中写入数据

代码:进程A

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{

    // 1.首先判断有名管道是否存在,存在就直接使用,不存在就创建
    int ret = access("fifo1", F_OK); //判断管道是否存在
    if (ret == 0)
    {
        printf("Pipe 1 has existed\n");
    }
    else
    {
        printf("Pipe 1 has not existed,need to create\n");
        int ret = mkfifo("fifo1", 0664); //第一个是文件路径,第二个是权限
        if (ret == -1)
        {
            perror("mkfifo");
            exit(0);
        }
    }
    ret = access("fifo2", F_OK); //判断管道是否存在
    if (ret == 0)
    {
        printf("Pipe 2 has existed\n");
    }
    else
    {
        printf("Pipe 2 has not existed,need to create\n");
        int ret = mkfifo("fifo2", 0664); //第一个是文件路径,第二个是权限
        if (ret == -1)
        {
            perror("mkfifo");
            exit(0);
        }
    }

    // 2. 只写的方式打开管道1
    int fdw = open("fifo1", O_WRONLY);
    if (fdw == -1)
    {
        perror("open");
        exit(0);
    }
    printf("打开管道fifo1成功,等待写入...\n");
    // 3. 只读的方式打开管道2
    int fdr = open("fifo2", O_RDONLY);
    if (fdr == -1)
    {
        perror("open");
        exit(0);
    }
    printf("打开管道fifo2成功,等待读取...\n");

    // 4.循环的写读数据
    char buf[128] = {}; //初始化一个内核缓冲区,fifo中的数据存在内核中
    while (1)
    {
        memset(buf, 0, 128); //清空buf
        //获取标准的输入
        fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
        //写端写数据
        ret = write(fdw, buf, strlen(buf));
        if (ret == -1)
        {
            perror("write");
            exit(0);
        }

        // 5. 读管道数据
        memset(buf, 0, 128);
        ret = read(fdr, buf, 128); //等待B写入才能再读
        if (ret <= 0)
        { //<0 调用失败;=0 read完数据
            perror("read");
            break;
        }
        printf("buf:%s\n", buf);
    }
    //关闭文件描述符
    close(fdw);
    close(fdr);
    return 0;
}

代码:进程B

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{

    // 1.首先判断有名管道是否存在,存在就直接使用,不存在就创建
    int ret = access("fifo1", F_OK); //判断管道是否存在
    if (ret == 0)
    {
        printf("Pipe 1 has existed\n");
    }
    else
    {
        printf("Pipe 1 has not existed,need to create\n");
        int ret = mkfifo("fifo1", 0664); //第一个是文件路径,第二个是权限
        if (ret == -1)
        {
            perror("mkfifo");
            exit(0);
        }
    }
    ret = access("fifo2", F_OK); //判断管道是否存在
    if (ret == 0)
    {
        printf("Pipe 2 has existed\n");
    }
    else
    {
        printf("Pipe 2 has not existed,need to create\n");
        int ret = mkfifo("fifo2", 0664); //第一个是文件路径,第二个是权限
        if (ret == -1)
        {
            perror("mkfifo");
            exit(0);
        }
    }

    // 2. 只读的方式打开管道1
    int fdr = open("fifo1", O_RDONLY); //另一端没打开,阻塞,等待另一端打开才继续进行
    if (fdr == -1)
    {
        perror("open");
        exit(0);
    }
    printf("打开管道fifo1成功,等待读取...\n");

    // 3. 只写的方式打开管道2
    int fdw = open("fifo2", O_WRONLY);
    if (fdw == -1)
    {
        perror("open");
        exit(0);
    }
    printf("打开管道fifo2成功,等待写入...\n");

    // 4.循环的读写数据
    char buf[128] = {}; //初始化一个内核缓冲区,fifo中的数据存在内核中
    while (1)
    {
        // 5. 读管道数据
        memset(buf, 0, 128);
        ret = read(fdr, buf, 128);
        if (ret <= 0)
        { //<0 调用失败;=0 read完数据
            perror("read");
            break;
        }
        printf("buf:%s\n", buf);

        memset(buf, 0, 128); //清空buf
        //获取标准的输入
        fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
        //写端写数据
        ret = write(fdw, buf, strlen(buf));
        if (ret == -1)
        {
            perror("write");
            exit(0);
        }
    }
    // 6. 关闭文件描述符
    close(fdw);
    close(fdr);
    return 0;
}

———————————————————————————————————————————

上述进程通信存在的问题:

只有当进程A发送多行数据时,B中只读取第一行数据,在终端只显示第一行,只有A进程再次收到进程B的数据后,A中的第二行才会从缓冲区内显示在进程B的终端中。

造成此结果的原因是,进程A、B读写在同一个进程中进行,read() 没有读到另一个进程的数据     会发送阻塞等待。

避免:创建一个子进程,用父进程实现写的功能,用子进程实现读的功能,互不干扰。

———————————————————————————————————————————

代码:进程A

 pid_t pid = fork();
    char buf[128] = {};
    if (pid > 0)
    {
        // 4.父进程用来写数据
        while (1)
        {
            memset(buf, 0, 128); //清空buf
            //获取标准的输入
            fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
            //写端写数据
            ret = write(fdw, buf, strlen(buf));
            if (ret == -1)
            {
                perror("write");
                exit(0);
            }
        }
    }
    else if (pid == 0)
    {
        // 5. 子进程读管道数据
        while (1)
        {
            memset(buf, 0, 128);
            ret = read(fdr, buf, 128); //等待B写入才能再读
            if (ret <= 0)
            { //<0 调用失败;=0 read完数据
                perror("read");
                break;
            }
            printf("buf:%s\n", buf);
        }
    }

代码:进程B

    pid_t pid = fork();
    char buf[128] = {}; //初始化一个内核缓冲区,fifo中的数据存在内核中
    if (pid > 0)
    {
        while (1)
        {
            // 5. 读管道数据
            memset(buf, 0, 128);
            ret = read(fdr, buf, 128);
            if (ret <= 0)
            { //<0 调用失败;=0 read完数据
                perror("read");
                break;
            }
            printf("buf:%s\n", buf);
        }
    }
    else if (pid == 0)
    {
        while (1)
        {
            memset(buf, 0, 128); //清空buf
            //获取标准的输入
            fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
            //写端写数据
            ret = write(fdw, buf, strlen(buf));
            if (ret == -1)
            {
                perror("write");
                exit(0);
            }
        }
    }



版权声明:本文为qq_57328462原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。