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

进程间通信 管道

在Linux中,管道是一种通信机制,用于将一个程序的输出直接连接到另一个程序的输入。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,它可以克服使用文件进行通信的两个问题,具体表现为限制管道的大小和读取进程可能工作得比写进程快。管道的思想是在内存中创建一个共享文件,从而使通信双方利用这个共享文件来传递信息。由于这种方式具有单向传递数据的特点,所以这个作为传递消息的共享文件就叫做“管道”。在管道的具体实现中,根据通信所使用的的文件是否具有名称,有“匿名管道”和“命名管道”。

匿名管道是一种具有亲缘关系的进程间的通信机制,它由创建它的进程及其子孙进程使用。匿名管道由pipe函数创建并打开。

命名管道克服了匿名管道只能在具有亲缘关系进程间通信的缺点,使不具有亲缘关系的进程间也能通过命名管道进行通信。命名管道由mkfifo函数创建。命名管道在文件系统中有对应的文件名。命名管道通过打开该文件名来打开管道,从而实现与其他进程的通信。

管道是连接两个进程的连接器(特殊文件)

匿名管道

当一个管道建立后,将获得两个文件描述符,分别用于对管道读取写入,通常将其称为管道的读端写端

image-20231202182312664

image-20231202182327485

所用到的函数:

#include <unistd.h>
int pipe(int pipefd[2]);

参数说明:

pip数组:存放两个文件描述符

  • pipefd[0]:存放管道读端文件描述符。
  • pipefd[1]:存放管道写端文件描述符。

返回值:

  • 调用成功,返回0
  • 调用失败,返回-

管道的读写操作

读规则
  1. 关闭管道的写端
close(fd[1]);
  1. 从管道读端fd[0]读出size个字符放到buf
read(fd[0], buf, size);
  1. 读完关闭管道的读端
close(fd[0]);
写规则
  1. 关闭管道的读端
close(fd[0]);
  1. buf中的长度为size的字符送到写端fd[1]
write(fd[1], buf, size);
  1. 写完关闭管道的写端
close(fd[1]);

例子:在父进程向管道内写入"Hello World\n",之后在子进程中读取内容。

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

int main()
{
    int fd[2];
    int ret = pipe(fd);
    char buf[100] = "Hello Wrold\n";
    if(ret == -1) {
        perror("pipe error");
        exit(1);
    }
    pid_t pd = fork();
    if(pd > 0) {
        // 关闭读端
        close(fd[0]);
        // 用写端,写入内容
        write(fd[1], buf, sizeof(buf));
        close(fd[1]);
        wait(NULL);
    } else if(pd == 0) {
        // 关闭写端
        close(fd[1]);
        // 从读端读取内容
        read(fd[0], buf, sizeof(buf));
        close(fd[0]);
        write(STDOUT_FILENO, buf, sizeof(buf));
        close(fd[0]);
    }
}

命名管道

命名管道与匿名管道的区别:

  • 匿名管道位于内存,只能用于有亲缘关系的进程通信
  • 命名管道位于文件系统中,可以实现不同进程之间的通信
  • 命名管道是一种双向通信管道,可以移动读/写模式打开

所用到的函数:

#include <sys/types.h>
#include <unistd.h>
int mkfifo(const char* pathname, mode_t mode);

参数说明:

  • pathname:创建的FIFO文件名
  • mode:规定FIFO文件的读写权限

返回值:

  • 成功时,返回0
  • 失败时,返回-1

创建一个叫np的命名管道

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
    if(mkfifo("np", 0644) < 0) {
        perror("Error!");
        exit(1);
    }
    return 0;
}

向管道写入内容:

#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <unistd.h>  
  
int main() {  
    pid_t fd;  
    // 指定文件的完整路径,如果文件不存在,将会创建  
    if ((fd = open("np", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {  
        perror("error");  
        exit(-1);  
    }  
    printf("%d\n", fd);  
    char buf[]  = "Hello World\n";  
    write(fd, buf, sizeof(buf));  
    close(fd);  
    printf("write success\n");  
    return 0;  
}

读出内容:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
    pid_t fd;
    char buf[100];
    if( (fd = open("np", O_RDONLY)) < 0) {
        perror("Error\n");
        exit(-1);
    }
    while( (read(fd, buf, sizeof(buf))) > 0) {
        write(STDOUT_FILENO, buf, sizeof(buf));
    }
    return 0;
}

http://www.kler.cn/a/154560.html

相关文章:

  • 【小白可懂】微信小程序---课表渲染
  • Python 打包教程:从零开始构建可分发的Python包
  • 深度学习:transpose_qkv()与transpose_output()
  • vue如何实现组件切换
  • 一文3000字从0到1带你进行Mock测试(建议收藏)
  • Tensorflow基本概念
  • 用两个队列实现栈
  • QT 中 QProgressDialog 进度条窗口 备查
  • mazing是什么软件?为什么选择iMazing
  • 【Redis】Redis的内部设计与实现
  • vue中中的动画组件使用及如何在vue中使用animate.css
  • go学习之goroutine和channel
  • 微信小程序获取定位显示在百度地图上位置出现偏差
  • vcomp140.dll是什么意思?vcomp140.dll缺失怎么修复的五个方法
  • WT2003H MP3语音芯片方案:强大、灵活且易于集成的音频解决方案
  • 给定一组经纬度如何判断某点是否在这组经纬度的范围之内(电子围栏实现代码)
  • 关于Maxscript你了解多少?
  • ChatGpt回答人工智能发展利大于弊的辩证论述
  • 同步加载、异步加载、延迟加载、预加载的区别
  • Java数据结构之《希尔排序》题目
  • 代码随想录算法训练营第39天| 62.不同路径 63. 不同路径 II
  • 吉他初学者学习网站搭建系列(4)——如何查询和弦图
  • NacosSync 用户手册
  • 苍穹外卖——删除购物车信息
  • Java流Stream使用详解(下)
  • 【JavaSE】API(学习笔记)