当前位置: 首页 > news >正文

Linux——管道通信

前言:大家好😍,本文主要介绍了Linux——管道通信

🌸格格Code的Linux🌸有关Linux的知识点都在这里,大家可以看看对自己有没有帮助🙋🙋🙋 

目录

一. 管道通信

1.基本概念

2.管道的类型

3. 管道通信的特点

一.有名管道

1. 单次管道通信

2.  持续管道通信

3. 调用信号 

二.无名管道

1. 使用pipe函数创建管道

2. 管道(pipe)进行进程间通信

 3. 管道和进程创建实现父子进程间通信


一. 管道通信

进程间通信(ipc):管道 信号量 共享内存 消息队列 套接字

写入管道的数据在内存

管道的通信方式:半双工(在同一时间内,数据只能单向流动。对于管道来说)

1.基本概念

管道通信(Pipe Communication)是操作系统中进程间通信(IPC,Inter-Process Communication)的一种基本方式。它可以让一个进程的输出作为另一个进程的输入并允许两个进程通过一个缓冲区进行通信,实现数据互传,这个缓冲区就是管道。

2.管道的类型

  1. 匿名管道(Anonymous Pipes)

    • 匿名管道是最基本的管道形式,它在内存中创建,没有在文件系统中对应的文件。

    • 匿名管道只能用于有共同祖先的进程之间(通常是父子进程)的单向通信。

    • 匿名管道是无结构的字节流,没有消息边界。

    • 匿名管道是只能在父子进程间使用的,它通过pipe()函数创建,并返回两个文件描述符,一个用于读,一个用于写。

  2. 命名管道(Named Pipes,FIFO)

    • 命名管道在文件系统中有一个对应的文件,可以通过文件名进行访问

    • 命名管道可以用于任意两个进程之间的通信,不限于父子进程。

    • 命名管道也是无结构的字节流,但可以通过文件名进行标识。

    • 命名管道是可以在任意进程间使用的,它通过mkfifo()或mknod()函数创建一个特殊的文件,然后通过open()函数打开,并返回一个文件描述符,用于读或写。

3. 管道通信的特点

  1. 单向性

    • 管道是单向的,数据只能从一端流向另一端。如果需要双向通信,需要创建两个管道。

    • 匿名管道只能单向通信,而命名管道可以设置为双向通信(通过创建两个命名管道)。

  2. 同步性

    • 管道的读写操作是同步的。写操作会阻塞,直到读操作从管道中读取数据;读操作会阻塞,直到写操作向管道中写入数据。

  3. 缓冲区

    • 管道使用内存缓冲区来存储数据,因此它的传输速度相对较快,但缓冲区大小有限。

  4. 无记录边界

    • 管道中的数据是无结构的字节流,没有记录边界,需要读写双方约定数据的格式和边界。

一.有名管道

有名管道(命名管道)fifo 单向命名管道通信可以在任意俩个进程间通信 但需要在同一个管道内

管道为空:read会阻塞

管道为满:write会阻塞

1. 单次管道通信

a.c代码 a.c写入管道 数据

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    int fdw = open("fifo", O_WRONLY); // 以只写方式打开命名管道
    if (fdw == -1) // 如果打开失败,返回-1
    {
        exit(1);
    }

    printf("fdw=%d\n", fdw);
    printf("input\n");

    char buff[128] = {0}; // 创建一个字符数组用于存储输入的数据
    fgets(buff, 128, stdin); // 从标准输入读取一行数据
    write(fdw, buff, strlen(buff)); // 将输入的数据写入到命名管道中

    close(fdw); // 关闭文件描述符
    exit(0); // 正常退出程序
}

 b.c代码 b.c读写入的数据  并打印出

 

单独运行输出不了必须同时运行  开俩个窗口

在./a中写入heelo  然后在b中输出了

写入的数据会通过命名管道传输到读端程序,并被打印出来

2.  持续管道通信

 

加个while循环就会一直通信

  • 读端可以不断地从管道中读取数据,直到满足某个条件(如读取到特定结束标志)。

  • 写端可以不断地向管道中写入数据,直到满足某个条件(如用户输入结束标志)

直至在写端./a中写入end才会关闭

 

3. 调用信号 

管道写端关闭:读端read返回0表示 EOF

管道读端关闭,写端写数据,会出发信号,SIGPIPE默认情况下会导致进程终止。

若直接ctrl+c关闭读端那么会触发信号 写端随便写个数据会直接退出(这里没有调用信号函数)

修改a.c加入信号并调用

fun函数接收一个参数 sigvoid func(int signum),其中 signum 是一个整型参数,表示信号的编号。它表示被捕获的信号的编号。函数体内,使用 printf 函数打印出这个信号编号

进程通过 signal 函数指定了 SIGPIPE 信号的处理方式,即调用 fun 函数。

void (*signal(int signum, sighandler_t handler))(int);

  • signum 参数指定了要处理的信号的编号。

  • handler 参数指定了当信号发生时应该调用的函数。

当读端关闭时,写端继续写会打印信号的值

  • <stdlib.h>:包含一些通用的工具函数,例如exit
  • <unistd.h>:提供了许多 UNIX 系统服务的函数原型,如文件操作、进程控制等。
  • <string.h>:字符串处理函数库,例如strlen
  • <fcntl.h>:文件控制选项相关的头文件,这里用于指定文件打开模式。

二.无名管道

无名管道只能在父子进程间通信。它在内存中创建,没有在文件系统中的对应文件,因此被称为“无名”或“匿名”

1. 使用pipe函数创建管道

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int fds[2]; // fds[0] 用于读,fds[1] 用于写
    if (pipe(fds) != 0) // 创建管道
    {
        exit(1); // 如果创建失败,退出程序
    }

    printf("fds[0]=%d\n", fds[0]); // 打印读端文件描述符
    printf("fds[1]=%d\n", fds[1]); // 打印写端文件描述符

    close(fds[0]); // 关闭读端
    close(fds[1]); // 关闭写端

    exit(0); // 正常退出程序
}

 

运行结果最后为3和4

 每次运行程序时输出的值可能会不同。但是,它们通常会是连续的整数,并且大于2(因为0、1、2被标准输入、输出和错误占用)。

  • 定义一个整型数组fds[2]用于存储管道的两个文件描述符fds[0]是读端,fds[1]是写端。

  • 使用pipe(fds)函数创建一个管道,如果创建失败(即返回值不为0),则调用exit(1)退出程序。

  • 使用printf函数打印出管道的读端和写端的文件描述符。

  • 使用close函数关闭管道的读端和写端。

  • 最后,使用exit(0)正常退出程序。

#include <unistd.h>

int pipe(int pipefd[2]);

  • pipefd 是一个整型数组,用于存储管道两端的文件描述符。这个数组必须有两个元素的空间。

    • pipefd[0] 用于管道的读端(接收数据的一端)。

    • pipefd[1] 用于管道的写端(发送数据的一端)。

    • pipe 函数是 POSIX 标准中定义的一个用于创建管道的系统调用,它允许两个相关的进程(通常是父子进程)之间进行单向通信。管道是一种半双工的通信方式,即数据只能沿一个方向流动。通过使用 pipe 函数,进程可以创建一个简单的通信通道,用于在它们之间传递数据。

2. 管道(pipe)进行进程间通信

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int fds[2]; // fds[0] 用于读,fds[1] 用于写
    if (pipe(fds) != 0) // 创建管道
    {
        exit(1); // 如果创建失败,退出程序
    }

    printf("fds[0]=%d\n", fds[0]); // 打印读端文件描述符
    printf("fds[1]=%d\n", fds[1]); // 打印写端文件描述符

    write(fds[1], "hello", 5); // 向管道写入字符串"hello"
    sleep(5); // 暂停5秒,让写操作有时间完成

    char buff[128] = {0}; // 创建一个缓冲区
    read(fds[0], buff, 127); // 从管道读入数据到缓冲区
    printf("read:%s\n", buff); // 打印读到的数据

    close(fds[0]); // 关闭读端
    close(fds[1]); // 关闭写端

    exit(0); // 正常退出程序
}

程序的主要功能是创建一个管道,通过管道写入数据,然后读取数据并打印出来。

  • 定义一个字符数组buff作为缓冲区,并使用read函数从管道的读端读取数据到缓冲区。

  • 使用printf函数打印出从管道读到的数据。

 3. 管道和进程创建实现父子进程间通信

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int fds[2]; // fds[0] 用于读,fds[1] 用于写
    if (pipe(fds) != 0) // 创建管道
    {
        exit(1); // 如果创建失败,退出程序
    }

    printf("fds[0]=%d\n", fds[0]); // 打印读端文件描述符
    printf("fds[1]=%d\n", fds[1]); // 打印写端文件描述符

    pid_t pid = fork(); // 创建子进程
    if (pid == -1)
    {
        exit(1); // 如果创建失败,退出程序
    }

    if (pid == 0)
    {
        close(fds[1]); // 子进程关闭写端
        char buff[128] = {0};//创建一个缓冲区buff
        read(fds[0], buff, 127); // 从管道读最多127个字符数据到缓冲区
        printf("child read:%s\n", buff); // 子进程打印读到的数据
        close(fds[0]); // 关闭读端
    }
    else
    {
        close(fds[0]); // 父进程关闭读端
        write(fds[1], "hello", 5); // 向管道写入5个字符串"hello"
        close(fds[1]); // 关闭写端
    }

    exit(0); // 正常退出程序
}
  • 使用fork函数创建一个子进程。fork函数返回两次:在父进程中返回子进程的PID,在子进程中返回0。

  • buff 是一个字符缓冲区,用于临时存储从管道中读取的数据。

  • pid_t 是一个数据类型,用于存储进程ID(PID)

  • 如果fork返回0,表示当前是子进程,执行子进程的代码:

    • 关闭管道的写端。

    • 定义一个字符数组buff作为缓冲区,并使用read函数从管道的读端读取数据到缓冲区。

    • 使用printf函数打印出从管道读到的数据。

    • 关闭管道的读端。

  • 如果fork返回非0值,表示当前是父进程,执行父进程的代码:

    • 关闭管道的读端。

    • 使用write函数向管道的写端写入字符串"hello"。

    • 关闭管道的写端。

相关文章:

  • C++标准模板库学习--函数模板返回值参数类型
  • Linux驱动开发之中断处理
  • 网页转图片的方法(超出可视范围的也可以)dom-to-image
  • 网编高级 day03
  • dify-1.0.1 + deepseek调用本地知识库
  • ASP4644四通道降压稳压器的工业高效电源管理方案
  • linux常用基本指令汇总
  • vue3:八、登录界面实现-忘记密码
  • Dump 文件介绍
  • Symmetry Protected Topological phases of Quantum Matter——对称性保护量子物质的拓扑相位
  • 2.PPP专题
  • SAP IBP for Supply Chain Certification Guide (Parag Bakde, Rishabh Gupta)
  • 【推荐项目】049-物流系统技术管理平台
  • 实验篇| CentOS 7 下 Keepalived + Nginx 实现双机高可用
  • 电气制作行业
  • Vim软件使用技巧
  • 前端登录鉴权全解析:主流方案对比与实现指南
  • 996引擎-自定义属性:配表 + 映射
  • 某大厂自动化工程师面试题
  • FFMPEG录制远程监控摄像头MP4
  • 湖南4个县市区被确定为野生蘑菇中毒高风险区:中毒尚无特效解毒药
  • 消息人士称俄方反对美国代表参加俄乌直接会谈
  • 美国务卿鲁比奥抵达会场,将参加俄乌会谈
  • 阿里上财年营收增6%,蒋凡:会积极投资,把更多淘宝用户转变成即时零售用户
  • 中国青年报:为见义勇为者安排补考,体现了教育的本质目标
  • 李峰已任上海青浦区委常委