进程间通讯--管道

本文介绍了UNIX系统中的管道通信机制,包括无名管道和命名管道。无名管道适用于父子进程间的通信,而命名管道则允许不相关进程间的数据交换。文中通过示例代码详细解释了如何创建和使用管道,并展示了管道的半双工特性,即单向通信。此外,还探讨了管道所能承载的最大字节数。
摘要由CSDN通过智能技术生成

管道

管道是UNIX系统中最古老的IPC(进程间通信)方式,所有UNIX系统都提供这种通信机制。
管道就是从一个进程连接到另一个进程的一个数据流

管道分为命名管道无名管道,在内核中申请一块固定大小的缓冲区,程序拥有写入读取的权利,都可以看成一种特殊的文件,具有固定的读端和写端,也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中;无名管道一般使用fork函数实现父子进程的通信,命名管道用于没有血缘关系的进程也可以进程间通信;面向字节流、自带同步互斥机制、半双工(对讲机),单向通信,两个管道实现双向通信。

无名管道

完成进程间通讯,需要建立管道。管道并非属于进程的资源,而是和套接字一样,属于操作系统。

建立管道的函数

#include <unistd.h>

int pipe(int filedes[2]);

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

  • filedes[0] 通过管道接收数据时使用的文件描述符,即管道出口。
  • filedes[1] 通过管道传输数据时使用的文件描述符,即管道入口。

fd[1]永远是写端,而fd[0]永远是读端

管道示意图如下
在这里插入图片描述
下面给出无名管道的示例代码:

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

int main()
{
	int fds[2];
	char str[] = "I love lzr";
	char buf[30];
	pid_t pid;

    pipe(fds);
	pid = fork();
	if(pid == 0){
		write(fds[1], str, sizeof(str));
	}
	else{
		read(fds[0], buf, 30);
		puts(buf);
	}
	return 0;
}

根据fork函数有关内容请点击右侧 fork函数
运行结果如下图
在这里插入图片描述
但是你会发现,一个管道只会单向传递,如果我们想双向传递怎么办呢,我们可以建立两个管道,这样子就可以进行数据的双向传递。

概念图如下
在这里插入图片描述
示例代码如下:

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

int main()
{
	int fds1[2], fds2[2];
	char str1[] = "I love sx";
	char str2[] = "I love lzr";
	char buf[30];
	pid_t pid;

	pipe(fds1), pipe(fds2);
	pid = fork();
	if(pid == 0)
	{
		write(fds1[1], str1, sizeof(str1));
		read(fds2[0], buf, 30);
		printf("Child proc output : %s \n", buf);
	}
	else
	{
		read(fds1[0], buf, 30);
		printf("Parent proc output : %s \n", buf);
		write(fds2[1], str2, sizeof(str2));
		sleep(3);
	}
	return 0;
}

在这里插入图片描述

命名管道

对比无名管道,无名管道只能用于父子之间的进程间通讯,而命名管道则不然,可以在不相关的进程间进行数据交换,FIFO本身是一种特殊的文件。

下面给出命名管道之间通讯的示例代码:

pipe4.c

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

int main(int argc, char** argv){
	int fd = open("FIFO", O_WRONLY);
	if (fd == -1){
		printf("fd less than 0");
		return 0;
	}

	while(1){
		char buff[128] = {0};
		fgets(buff, 127, stdin);
		write(fd, buff, strlen(buff));
		if(strncmp(buff, "end", 3) == 0){
			break;
		}
	}
	close(fd);
	return 0;
}

pipe5.cpp

#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#include <iostream>

using namespace std;

int main(){
	int fd = open("FIFO", O_RDONLY);
	if(fd == -1){
		cout << "fd less than 0" << '\n';
		return 0;
	}

	char buff[128] = {0};
	while(strncmp(buff, "end", 3) != 0){
		read(fd, buff, 127);
		cout << buff << '\n';
		memset(buff, '\0', 128);
	}
	close(fd);
	return 0;
}

运行结果如下图:
在这里插入图片描述
思路如图所示:

在这里插入图片描述

一定要在命令行加上上 mkfifo FIFO 这条语句,因为不然的话就会发生open错误,这也是我经历过的(也可以不加,不加的话就要在程序中创建FIFO文件)。但是这样子也只能实现单向通讯。这也是管道的特点,半双工的特性。其实就类似于对讲机,“地瓜地瓜我是土豆” “地瓜收到" ,只能一个人发送,一个人收到,这就是半双工,也就是单向通讯。

管道所能承担的最大字节数

不止这些,我自己测试了一下管道能承担的最大字节数。

示例代码如下:

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

int main()
{
	int fds[2];
	char str = 'a';
	pid_t pid;
    
	pipe(fds);
	pid = fork();
	if(pid == 0);
	else
	{
        int count = 0;
		while(1){
            write(fds[1], &str, sizeof(str)); //往管道中写入一个字节
			printf("%d\n", ++count);  //实时输出已经容纳的字节
		}
	}
	return 0;
}

运行结果如下:
在这里插入图片描述
由此可知,管道最大容纳的字节数为65536个字节,也就是64k,后面我上网搜索也是和我的验证结论一样,因此证明了我的压测结果没有错误。
以上就是我的总结的内容,如果问题,欢迎评论留言哦!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值