Linux高级 2019-5-12上午

1.匿名管道

1.1 匿名管道,用于进程间通信

  • 通过函数 pipe() 实现匿名管道;

1.2 函数 pipe()

  • 函数形式: int pipe(int pipefd[2]);
  • 参数: 一个数组;

1.3 调用 pipe() 函数后在内核空间创建一个内核缓冲区,这个缓冲区是进程共有的,为4096byte的环形队列

1.4 进程打开一个文件,会与三个表发生关联:文件描述符表、文件表、索引节点表

  • 对于文件描述符表,有下面几个标准符号:
    • 标准输入:0
    • 标准输出:1
    • 标准出错:2
    • 指向读端:3 fd[0]
    • 指向写端:4 fd[1]

1.5 向管道写数据 通过fd[1] ,向管道写数据 通过fd[0]

1.6 匿名管道的限制

  • 只能在具有亲缘关系的进程间进行通信

1.7 管道的特性

  • 数据流通具有方向性;

1.8 在使用匿名管道之前需要确定通信方向,父子进程关闭掉无用的读写,例如父进程 close(fd[0]) ,子进程 close(fd[1])

1.9 完成一个匿名管道

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

#define MSG "HELLO"

int main()
{
	int fd[2];
	pid_t pid;
	// 先创建管道,避免子进程重复创建管道
	pipe(fd);
	pid = fork();
	if(pid > 0)
	{
		printf("Parent:%d process running...\n", getpid());
		close(fd[0]);
		write(fd[1], MSG, strlen(MSG));
		close(fd[1]);
		while(1);
	}
	else if(pid == 0)
	{
		printf("Child:%d process running...\n", getpid());
		char buf[1024];
		int len;
		bzero(buf, sizeof(buf));
		close(fd[1]);
		len = read(fd[0], buf, sizeof(buf));
		close(fd[0]);
		exit(0);
	}
	else
	{
		perror("fork call error");
		exit(0);
	}

	return 0;
}

1.10 匿名管道使用时的几种特殊情况

  • 1.读端开启,写端关闭:读端读完管道内数据后,再次读返回0(相当于读到文件末尾);
  • 2.写端开启,读端关闭:尝试向管道内写数据,内核向进程发送 sigpipe 信号,导致写端终止;
  • 3.读写端开启,写端没有进行写数据操作:读端读完管道内数据后,再次读时阻塞;
  • 4.读写端开启,读端没有读数据:写端写满管道后,再次写时阻塞;

1.11 管道的优缺点

  • 1.匿名管道单工工作,只支持单向数据流;
  • 2.没有名字,无法分辨;
  • 3.只能用于具有亲缘关系的进程之间;
  • 4.管道的缓冲区有限,管道存在于内存中,在创建管道时为缓冲区分配一个页面大小;
  • 5.管道所传送的是无格式字节流,这就要求管道的读端和写端必须事先约定好数据的格式;

2.有名管道

2.1 创建步骤

  • 1.首先在终端 mkfifo hello ,创建一个有名管道;
  • 2.在分别完成读端和写端;
    • 写端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MSG "Hello SLAM"

int main(int argc, char** argv)
{
	if(argc < 2)
	{
		printf("ERROR! TOO LESS ARGVS,PLS INPUT LIKE:\n");
		printf("./write NAME\n");
		exit(0);
	}
	int fd = open(argv[1], O_WRONLY);
	write(fd, MSG, strlen(MSG));
	close(fd);

	return 0;
}
  • 读端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	if(argc < 2)
	{
		printf("ERROR! TOO LESS ARGVS,PLS INPUT LIKE:\n");
		printf("./read NAME\n");
		exit(0);
	}
	int fd;
	fd = open(argv[1], O_RDONLY);
	char buf[1024];
	bzero(buf, sizeof(buf));
	int len = read(fd, buf, sizeof(buf));
	close(fd);
	printf("%s is from %s\n", buf, argv[1]);

	return 0;
}
  • 3.首先 gcc 02-pipe_write.c -o write ,生成一个 write 可执行文件作为写端;再 gcc 02-pipe_read.c ,生成一个 read 可执行文件作为读端;
  • 4.在一个终端中输入 ./write hello ,在另一个终端中输入 ./read hello ,则会发现在读端的终端上输出了 Hello SLAM is from hello

2.2 注意事项

  • 1.虽然我们将 有名管道 作为一个文件来使用,但是有名管道并不会被写入数据,在运行 write 时,有名管道并不改变大小;当 read 将管道中的数据读出去之后,管道同样不会改变大小;有名管道文件的大小始终为0,只是为两个进程提供一个类似于借口一样的东西;
  • 2.有名管道文件负责提供内核缓冲区访问方式(读写文件描述符),无法存储数据;
  • 3.使用有名管道时,必须以读写方式进行访问,若只是用一种方式就会阻塞,知道两种访问方式同时存在时才能进行访问;
  • 4.并不一定需要多个进程才能完成有名管道的访问,一个进程中同时存在读写方式,则在该进程中即可完成有名管道的使用。

2.3 有名管道的特殊情况

  • 1.一个写端,一个读端(多个读序列):读阻塞只对第一个读操作有效,对其他的读操作置为非阻塞管道保证数据读写完整;
  • 2.管道写时,不同的数据量可能对管道的机制进行改变;
  • 3.写入的数据小于管道缓冲区(4096),管道帮助保证数据的原子性,保证读写完整;
  • 4.写入的数据大于管道缓冲区(4096),取消数据原子保护性,数据切片分割;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值