Linux - 管道

进程间通信-管道

一、管道简述

  • 管道是Unix中最古老的进程间通信的形式。
  • 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道
  • 我们通常把是把一个进程的输出连接或“管接”(经过管道来连接)到另一个进程的输入
  • 管道实现通信原理
    • 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不 到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
    • 在这里插入图片描述

二、在shell中使用管道

  • 链接shell命令:把一个进程的输出直接馈入另一个的输入,命令格式如下
  	      command1 | command2 | command3

操作符是:”|”,它只能处理经由前面一个指令传出的正确输出信息,对错误信息没有直接处理能力。然后,传递给下一个命令,作为标准的输入.

管理命令的输出说明:

【指令1】 正确输出,作为 【指令2】的输入 然后**【指令2】的输出作为【指令3】的输入【指令3】输出就会直接显示在屏幕**上面了。

通过管道之后【指令1】和【指令2】的正确输出不显示在屏幕上面

【提醒注意】:

  1. 管道命令只处理前一个命令正确输出,不处理错误输出;

  2. 管道命令右边命令,必须能够接收标准输入流命令才行;

举例应用:

  1. 读出logcat.log文件的内容,通过管道转发给grep作为输入内容
cat logcat.log | grep –n ‘ActivitManager’
  1. who|grep tty|wc –l 显示从控制台登录的人数
who|grep tty|wc –l 

三、pipe管道

3.1- pipe函数说明

管道是一种最基本的IPC机制,可由pipe函数创建:

#include <unistd.h>
int pipe(int filedes[2]);
  • pipe管道作用于有血缘关系的进程之间,通过fork来传递
  • 调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个
    写端,然后通过filedes参数传出给用户程序两个文件描述符filedes[0]指向管道的读
    端,filedes[1]指向管道的写端
    (很好记,就像0是标准输入1是标准输出一样)。所以管道 在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。
  • pipe函数调用成功返回0,调用失败返回-1

3.2- pipe函数实现通信的原理

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

3.3-应用示例: 父进程写,子进程读

#include <unistd.h>
#include <stdio.h>
int main()
{
	int fd[2];
	pid_t pid;
	char str_write[1024] = "hello, I am content.";
	char str_read[1024] = {0};

	//创建管道,参数fd作为要传出去的两个文件描述符 
	if(pipe(fd) < 0)
	{
		//创建管道失败
		perror("pipe");
		exit(1);	
	}
	
	//创建子进程 
	pid = fork();
	
	//fd[0] 读端 , fd[1] 写端
	
	//父进程 
	if(pid > 0)
{
		close(fd[0]);//父进程 关闭读端 
		write(fd[1],str_write,strlen(str_write));
		wait(NULL);//立即阻塞父进程,等待子进程退出 
	}
	//子进程 
	else if (pid == 0)
	{
		int len;
		close(fd[1]);//子进程 关闭写端 
		len = read(fd[0],str_read,sizeof(str_read));
		write(STDOUT_FILENO,str_read,len);//把str_read输出到终端 
	 } 
	
	return 0;
}

3.4- 管道读写规则

  • 如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生
  • 没有数据可读时,read调用就会阻塞,即进程暂停执行,一直等到有数据来到为止。
    如果管道的另一端已经被关闭,也就是没有进程打开这个管道并向它写数据时,read调用就会阻塞
  • 如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;
  • 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。
  • 向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

四、fifo有名管道

4.1-fifo有名管道简述

  • 匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
    如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道

  • 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

    •  $ mkfifo filename
      
  • 命名管道也可以从程序里创建,相关函数有:

  • 		int mkfifo(const char *filename,mode_t mode);
     	```
    
  • mkfifo创建的FIFO文件的文件属性的第一位是p

4.2- FIFO的打开规则:

  • 如果当前打开操作是为而打开FIFO时,若已经有相应进程为而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置了阻塞标志);或者,成功返回(当前打开操作没有设置阻塞标志)。
  • 如果当前打开操作是为而打开FIFO时,如果已经有相应进程为而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作设置了阻塞标志);或者,返回ENXIO错误(当前打开操作没有设置阻塞标志)。

4.3-应用示例

用来写FIFO文件:fifo_w.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
// write
void sys_err(char *str,int exitno)
{
	perror(str);
	exit(exitno);
}

int main(int argc, char*argv[])
{
	int fd;
	char buf[1024] = "hello world\n";
	if(argc < 2)
	{
		printf("enter fifoname\n");
		exit(1);
	}
	fd = open(argv[1],O_WRONLY);
	if(fd<0)
	{
		sys_err("open",1);
	}
	write(fd,buf,strlen(buf));
	close(fd);
	return 0;
}

用来读FIFO文件:fifo_r.c

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

//read

void sys_err(char *str,int exitno)
{
        perror(str);
        exit(exitno);
}

int main(int argc, char*argv[])
{
        int fd;
        char buf[1024];
        int len;
	 if(argc < 2)
         {
                printf("enter fifoname\n");
                exit(1);
         }
        fd = open(argv[1],O_RDONLY);
        if(fd<0)
         {
                sys_err("open",1);
         }
        len= read(fd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,len);

	 close(fd);
        return 0;
}

终端上测试:

1.创建FIOF文件

2.编译文件
在这里插入图片描述
3.在终端1上执行fifo_r(用来读 创建的 fifo1文件中的数据)
但是现在没有进程为而打开该fifo1,所以终端1被阻塞


4.打开终端2,执行fifo_w(用来向 创建的 fifo1文件中写入数据)

5.此时切换回终端1,可以看到已经读到数据
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux是一种操作系统,而-bash是Linux中的一种shell(命令行解释器),它允许用户在命令行中输入命令并执行它们。-bash是Linux默认的shell之一,它提供了许多有用的功能和命令,使用户能够更轻松地管理和操作系统。 ### 回答2: Linux -bash 是指 Linux 系统中的 Bash(Bourne Again SHell)终端或命令行界面。 Bash 是一种常用的 Unix shell,它是用于管理和执行命令行操作的基础工具。它允许用户在 Linux 系统上输入和执行各种命令,与系统进行交互,并管理文件和文件夹。 Linux -bash 提供了一个交互式环境,用户可以在其中执行各种命令。它可以用于执行系统管理任务,如安装软件包、配置网络设置、管理用户和权限等。此外,还可以使用 bash 脚本编写批量处理任务,实现自动化和脚本化操作。 在 -bash 终端中,用户可以使用各种命令来探索文件系统、浏览文件和文件夹、编辑文本文件等。用户可以通过输入命令和参数,实现不同的操作和功能,比如复制、移动、删除文件,修改文件权限等等。 -bash 终端也提供了强大的命令行编辑和历史纪录功能。用户可以使用上下箭头键浏览之前输入的命令,并进行修改和再次执行。此外,可以使用 Tab 键进行自动完成操作,节省输入命令的时间和工作量。 总而言之,Linux -bash 是 Linux 系统中常用的命令行界面,在系统管理、文件操作和批处理方面提供了丰富的功能和灵活性,是 Linux 用户和系统管理员必不可少的工具之一。 ### 回答3: Linux的-bash是一种命令行解释器,也称为Bourne Again SHell。Bash是Unix操作系统中最常用的shell之一,由于Linux是基于UNIX的,因此Bash也成为了Linux中最常用的shell。 -bash表示当前用户所使用的shell环境是Bash。在Linux系统中,当我们打开终端或者SSH登录到服务器时,会自动进入一个shell环境,这个环境中我们可以使用各种命令来执行各种操作。 Bash是一个功能强大且灵活的shell,它支持大量的命令,可以用于管理和操作文件、目录、进程、权限、网络等各个方面。通过Bash,我们可以输入命令并执行,也可以编写shell脚本来进行自动化操作。 在-bash下,我们可以使用各种命令来管理Linux系统,比如ls命令用于列出当前目录下的文件和子目录,cd命令用于切换目录,pwd命令用于显示当前所在的目录,mkdir命令用于创建新的目录,rm命令用于删除文件和目录,等等。 此外,Bash还支持各种运算符和控制结构,允许我们编写复杂的shell脚本来自动化任务。我们可以使用if语句来进行条件判断,使用for和while循环来进行重复操作,还可以通过管道(|)来连接多个命令,实现更复杂的操作。 总之,Linux的-bash是一种强大的命令行解释器,它为我们提供了丰富的命令和功能,使我们能够高效地管理和操作Linux系统。无论是日常使用还是系统管理,熟练掌握-bash都是非常重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值