进程间通信 管道

在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;
}
  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

golemon.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值