网络编程之 进程间的通信之管道的使用

如何使用管道是进程间通信的关键

博主先声明一下,关于处理进程创建以及销毁的方法。
       “子进程究竟何时终止????调用waitpid函数后还要无休止的等待子进程终止吗???”,这显然会是一个问题。因为父进程往往与子进程一样繁忙,因此我们不能只调用waitpid函数来等待子进程终止。那么我们应该怎么办呢???
      这就要涉及到我们后面要了解的内容了,信号的概念,我们可以制作信号捕捉器,来完美解决这个问题,由于信号的知识点较多也比较复杂所以博主将往后推移了。

                    那我们就开始吧!!

如何理解进程间通信

      进程 通信意味着两个不同进程间可以交换数据,为了完成这一点,操作系统中应提供两个进程可以同时访问的内存空间(我们也叫缓冲区。)
      我们先看一下比较专业的解答吧。
      Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。
      其实就是进程一旦创建完成它就拥有完全独立的内存结构(0到4G的空间pcb控制块等等),就连通过 fork()创建的子进程也不会与父进程共享内存空间。因此我们就必须想想其他的办法完成进程间的通信了。只要有两个进程由可以同时访问的内存空间,那么进程间就可以通过此空间进行数据交换了。----------->这就是进程间通信。

啦啦啦啦
那么如何实现我们上面所说的呢??这似乎也是一件麻烦事啊????
在这里插入图片描述
      别担心,管道能帮助我们实现这个目标。
                                在这里插入图片描述

博主在这里唠叨一句下面的方法都能实现进程间通信,但是展开说实在太费篇幅,博主就简单提一提,如果有感兴趣的朋友可以去查一下相关的资料。

          在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有:
① 管道 (使用最简单)
② 信号 (开销最小)
③ 共享映射区 (无血缘关系)
④ 本地套接字 (最稳定)

管道是什么?

            既然我们要用到管道的话,那我们就先来聊一聊什么是管道吧。

IPC:下面给出百度百科的解释在这里插入图片描述

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
① 数据自己读不能自己写。
② 数据一旦被读走,便不在管道中存在,不可反复读取。
③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。(这就是半双工通信。)
④ 只能在有公共祖先的进程间使用管道。
(希望大家能记住上面的,还是比较重要的。)

给出管道的模型:
在这里插入图片描述

通过上图我们可以看到,为了完成进程间通信(因为进程间的通信不能直接完成,所以我们不得不使用管道),我们需要创建管道。管道不属于进程的资源。而是和套接字一样,属于操作系统(也就不是fork()锁复制的对象)。所以,两个进程之间可以通过操作系统提供的内存空间进行通信。

下面给出创建管道的函数:

#include<unistd.h>

int pipe(int pipefd[2]);
	-->成功:返回 0
	   失败:返回 -1

           函数调用成功返回read()/write()两个文件描述符。无需open(),但需手动close()。
          规定:fd[0] → read(); fd[1] → write(),就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区

其实当你要使用管道时,博主在这里可以给你一些使用的小方法来帮助你去理解一些代码.

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

#define BUF_SIZE 30

int main(void) {
	int fds[2];//因为你要调用 int pipe(int pipefd[2]) 这个函数所以你需要创建一个 int型的数组
	char str[] = "Who are you?";	//这个是你要写出去的字符串
	char buf[BUF_SIZE];	//用来接收的数组
	pid_t pid;//用来接收 fork()的返回值,来判断 父子进程

	pipe(fds);	//创建管道
	pid = fork();	//创建进程
	if (pid == 0) {	//子进程
		write(fds[1], str, sizeof(str));	//将字符串 "Who are you?"写出去
	} else {	//父进程
		read(fds[0], buf, BUF_SIZE));	//将独到的字符串写到 buf数组里面 该数组大小为 BUF_SIZE
		puts(buf);	//输出
	}
	return 0;
}

在这里插入图片描述

大家对于管道的理解到这里就行了,鉴于书中还有单管道同时进行读写,这是不推荐使用的。

不推荐这种

在这里插入图片描述

博主推荐的是下面这种方式使用管道在这里插入图片描述
为了完成这个模式我们需要使用以下代码:

在这里插入图片描述
有了博主上面的讲解大奖看懂这个代码应该是很轻松地了。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值