百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Linux进程间通信——管道

bigegpt 2024-08-28 12:27 5 浏览

管道

  • 什么是管道?
    一个进程连接到另一个进程的一个数据流称为一个“管道”。

匿名管道pipe

  • 用于父子间的通信
  • 管道最大64K,由环形队列组成
  • 需要占用两个文件描述符,分别作为管道读端、写端
  • 管道是半双工的,需要确定通信方向
    父写子读,关闭父读、子写
    子写父读,关闭子读、父写
  • 优点:稳定、经典

pipe函数原型

头文件:<unistd.h>

int pipe(int file_descriptor[2]);

功 能:创建一无名管道
参 数:file_descriptor:文件描述符数组,其中file_descriptor[0]表示读端,file_descriptor[1]表示写端
返回值:成功返回0,失败返回-1

开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。


1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端。
2、父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
3、父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里写,子进程可以从
4、管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。

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

#define MAXLINE 80

int main(void)
{
	int n;
	int fd[2];
	pid_t pid;
	char line[MAXLINE];

	if (pipe(fd) < 0) 
	{
		perror("pipe");
		exit(1);
	}
	if ((pid = fork()) < 0) 
	{
		perror("fork");
		exit(1);
	}
	if (pid > 0) // 父进程 
	{ 
		close(fd[0]);//关闭读端
		write(fd[1], "hello world\n", 12);
		wait(NULL);
	}
	else  //子进程
	{
		close(fd[1]);//关闭写端
		n = read(fd[0], line, MAXLINE);
		write(STDOUT_FILENO, line, n);
	}
	return 0;
}

运行结果

注意事项

  • 如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生
  • 写端未写完,写端暂时无数据,读端再次去读,read发生阻塞(读太快)
  • 读端未读完,写端满了,写端再次写,write发生阻塞(写太快)
  • 读端关闭,写端写数据,产生SIGPIPE信号,默认会终止进程
  • 写端关闭,当数据读完,再次读返回0

Linuxc/c++服务器开发高阶视频,电子书学习资料后台私信【架构】获取

有名管道fifo

pipe是有血缘关系进程之间的通信,那么当没有血缘关系的进程想要通信怎么办?

  • 创建一个有名管道fifo(也叫做named pipe),解决无血缘关系的进程通信
  • fifo是一个设备文件,本身无大小,在文件系统中以文件名的形式存在,因此即使进程与创建fifo的进程不存在血缘关系也依然可以通信,前提是可以访问该路径。
  • fifo总是遵循先进先出的原则,即第一个进来的数据会第一个被读走

与匿名管道pipe的区别

  • 提供了一个路径名与之关联,以fifo文件的形式存储于文件系统中,能够实现任何两个进程之间通信。而匿名管道对于文件系统是不可见的,它仅限于在父子进程之间的通信。 但是fifo底层是由pipe实现的。

如何创建fifo?

  • 命令行上创建
  • 程序内创建
    头文件:
    #include <sys/types.h>
    #include <sys/stat.h>
    函数原型:
    int mkfifo(const char *pathname, mode_t mode);

做个测试,分别写两个程序,一个写,一个读
写进程

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

int main(int argc, char* argv[])
{
	int fd;
	char buff[1024] = "hello world\n";

	if (argc < 2)
	{
		printf("enter you fifoname\n");
		exit(1);
	}
	fd = open(argv[1], O_WRONLY);//只写方式打开

	if (fd < 0)
	{
		perror("open\n");
	}

	write(fd, buff, strlen(buff));//写入hello world
	close(fd);

	return 0;
}

读进程

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

int main(int argc, char* argv[])
{
	int fd;
	int len;
	char buff[1024] = "hello world\n";

	if (argc < 2)
	{
		printf("enter you fifoname\n");
		exit(1);
	}
	fd = open(argv[1], O_RDONLY);//只写方式打开

	if (fd < 0)
	{
		perror("open\n");
	}

	len = read(fd, buff, sizeof(buff));
	write(STDOUT_FILENO, buff, len);
	close(fd);

	return 0;
}

测试结果如下


首先myfifo是我们提前创建好的fifo管道文件,然后执行写进程,再执行读进程。读到了hello world,执行前后myfifo文件大小都为0

注意事项

  • 当只写打开FIFO管道时,如果没有FIFO没有读端打开,则open写打开会阻塞。
  • FIFO内核实现时可以支持双向通信(pipe单向通信,因为父子进程共享同一个file结构体)
  • FIFO可以一个读端,多个写端;也可以一个写端,多个读端。

相关推荐

Go语言泛型-泛型约束与实践(go1.7泛型)

来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...

golang总结(golang实战教程)

基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...

Go 官宣:新版 Protobuf API(go pro版本)

原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...

Golang开发的一些注意事项(一)(golang入门项目)

1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...

golang 托盘菜单应用及打开系统默认浏览器

之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...

golang标准库每日一库之 io/ioutil

一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...

文件类型更改器——GoLang 中的 CLI 工具

我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...

Go (Golang) 中的 Channels 简介(golang channel长度和容量)

这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...

Golang引入泛型:Go将Interface「」替换为“Any”

现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...

一文带你看懂Golang最新特性(golang2.0特性)

作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...

Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移

以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...

Golang使用grpc详解(golang gcc)

gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...

Etcd服务注册与发现封装实现--golang

服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...

Golang:将日志以Json格式输出到Kafka

在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...

如何从 PHP 过渡到 Golang?(php转golang)

我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...