有名管道实现进程间通信

在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);
            }
        }
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
匿名管道有名管道都是Linux系统中用于进程通信的机制,它们的主要差异在于命名方式和使用方法。 匿名管道是一种无名的管道,它只能用于在父进程和子进程传递数据。匿名管道只能在创建它的进程及其子进程使用,其他进程无法访问。匿名管道的创建使用pipe系统调用,创建后可以使用文件描述符进行读写操作。匿名管道的读写是基于先进先出的队列,数据只能单向流动。例如,以下代码演示了如何使用匿名管道在父进程和子进程传递数据: ``` #!/bin/bash # 创建匿名管道 pipe=$(mktemp -u) mkfifo $pipe # 在子进程中写入数据 echo "hello from child process" > $pipe # 在父进程中读取数据 read line < $pipe echo "received data: $line" # 清理管道 rm $pipe ``` 有名管道也被称为FIFO管道,它是一种带有名称的管道,可以用于不同进程的数据传输。有名管道可以在任意进程中使用,只需要知道管道的名称即可。有名管道的创建使用mkfifo命令,创建后可以使用文件描述符进行读写操作。有名管道的读写也是基于先进先出的队列,数据只能单向流动。例如,以下代码演示了如何使用有名管道在两个进程传递数据: ``` #!/bin/bash # 创建有名管道 pipe=/tmp/myfifo mkfifo $pipe # 启动一个进程管道写入数据 echo "hello from process A" > $pipe & # 读取管道中的数据 read line < $pipe echo "received data: $line" # 清理管道 rm $pipe ``` 总的来说,匿名管道适用于父子进程的数据传输,而有名管道适用于任意进程的数据传输。在使用管道进行进程通信时,需要注意管道的读写顺序,否则会导致读取或写入失败。另外,管道的容量是有限的,如果写入的数据超过了管道的容量,会导致写入阻塞。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值