系统编程-管道

管道

目录

管道

1、管道的特点

2、无名管道的使用步骤

(1)在进程中使用 pipe 函数来获取管道的文件描述符

(2)使用 fork 函数来创建子进程

(3)通过获取到的文件描述符来进行数据的传输

(4)当管道不再使用的时候 需要进行关闭

3、有名管道的使用步骤

(1)创建一个有名管道出来

(2)打开有名管道 (有名管道的使用方式)

(3)通过打开的有名管道进行数据的操作

(4)关闭有名管道

4、删除有名管道函数

使用有名管道实现双向通信,用两根管道


引入:

  • 信号可以实现进程间的交互 但是没法发送数据。

  • 管道可以实现数据的传输

  • linux 下一切都是文件,管道也是一种文件 我们可以通过文件操作来进行数据的传输

-- 什么是进程间通信?

        每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

1、管道的特点

-- 1 先进先出

  • 数据被一个进程读出后,将被从管道中删除,其他读进程将不能再读到这些数据。管道的内容读完后不会保存。

-- 2 单向

  • 数据的流通方向的单向的,一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。

-- 3 管道为空

  • 无法读出数据 会读阻塞(进程试图读空管道时,进程将阻塞)

-- 4 管道为满

  • 写堵塞(管道已经满时,进程再试图向管道写入数据,进程将阻塞。)

  • 管道大小 64KB

alt text

alt text

  • 直接将1024这一块区域写进文件,并没有对该地址的空间做出改变,所以是可以的。

-- 5 管道有两种

  • 无名管道
    -- 没有名字的管道 只能让亲缘(父子)进程使用

  • 有名管道
    -- 在同一个操作系统下 用任意的两个进程都可以使用

-- 6 管道是单向的,一边要么读,一边要么写,不可以又读又写,想要一边读一边写,那就创建2个管道

-- 当进程退出之时,管道也随之释放,与文件保持一致


2、无名管道的使用步骤

(1)在进程中使用 pipe 函数来获取管道的文件描述符

-- 函数头文件

  • #include <unistd.h>

-- 函数的原型

  • int pipe(int pipefd[2]);

-- 函数的作用:

  • 调用该函数可以创建一个无名管道用于父子进程间通信
  • !!!该函数需要在 fork 之前来调用否则会创建两根管道

-- 函数的参数

  • 函数的参数用于返回无名管道的读端口和写端口对应的文件描述符
  • int pipefd[2]:一个 int 类型的数组
  • pipefd[0] 对应读端口
  • pipefd[1] 对应写端口

-- 函数的返回值:

  • 成功返回:0
  • 失败返回:-1
(2)使用 fork 函数来创建子进程
  • pid_t fork(void);
(3)通过获取到的文件描述符来进行数据的传输

-- 因为我们获取的是文件描述符,所以可以直接使用 read 和 write 函数来进行数据的写入和读取

  • ssize_t read(int fd, void *buf, size_t count)
  • ssize_t write(int fd, const void *buf, size_t count)

注:任何的数据传输,接收方接收的数据类型尽量的要跟发送方的一致

alt text

alt text

alt text

(4)当管道不再使用的时候 需要进行关闭

-- 调用 close 函数即可

  • 1 写端口彻底关闭 但是管道中还有数据 读端口可以正常读取 数据读取完毕之后 管道自动关闭
  • 2 读端口彻底关闭 写端口不可以正常写入

alt text

  • 要想彻底关闭管道,需要父子进程都进行 close 操作
    父进程关闭读写端口,子进程关闭读写端口 

    alt text


-- 向管道中写数据,从管道中读数据

alt text

alt text


3、有名管道的使用步骤

-- 因为无名管道使用范围有限(只能在父子进程之间),为了让任意的两个进程都可以使用管道通信,我们就可以用有名管道.

-- 有名管道的特点跟无名管道无区别

(1)创建一个有名管道出来

-- 使用指令创建

alt text

-- 使用函数创建

-- 函数头文件

  • #include <sys/types.h>
  • #include <sys/stat.h>

-- 函数原型

  • int mkfifo(const char *pathname, mode_t mode)

-- 函数的作用:

  • 根据参数来创建一个有名管道文件

-- 函数的参数:

  • pathname:路径和文件名
  • mode:有名管道的文件权限

-- 函数的返回值:

  • 成功返回 0
  • 失败返回 -1

alt text

(2)打开有名管道 (有名管道的使用方式)
  • 使用 open 函数来对有名管道进行打开
  • 有名管道必须要让两个进程同时调用 open 函数才可以打开成功
  • 而且一个进程以只读的方式 一个进程以只写的方式
  • 要想打开有名管道 必须要凑够可读可写这两个权限
(3)通过打开的有名管道进行数据的操作
  • read 和 write 函数来进行数据的写入和读取
  • ssize_t read(int fd, void *buf, size_t count)
  • ssize_t write(int fd, const void *buf, size_t count)
  • 任何的数据传输,接收方接收的数据类型尽量的要跟发送方的一致
(4)关闭有名管道
  • 读端先关闭 写端无法使用
  • 写端先关闭 但是管道中有数据 读端口仍可进行读取

4、删除有名管道函数

-- 函数头文件

  • #include <unistd.h>

-- 函数原型

  • int unlink(const char *pathname)

-- 函数的作用

  • 删除有名管道文件

-- 函数的参数:

  • pathname:填写有名管道文件

-- 函数的返回值:

  • 成功返回 0
  • 失败返回 -1

使用有名管道实现双向通信,用两根管道

alt text

alt text

alt text

-- rr.c

#include "stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "unistd.h"
int main(int argc,char*argv[])
{
    if(argc<3)
    {
    	printf("格式输入有误!\n");
    	return -1;
    }
    
    
    char buff1[30]={0};
    char buff2[30]={0};
    
    pid_t pid = fork();
    if(pid == 0)
    {
    while(1){
			//sleep(1);
			int fd_r = open(argv[1],O_RDONLY);
			int ret = read(fd_r,buff1,30);
			if(ret>0){
			printf("接收到%d个字节\n",ret);
			printf("buff1:%s\n",buff1);
			}else {
				break;
			}
			memset(buff1,0,30);
			close(fd_r);
		}
    }else if(pid >0){
    while(1){
    		int fd_w = open(argv[2],O_WRONLY);
			scanf("%s",buff2);
			write(fd_w,buff2,strlen(buff2));
			perror("write");
			close(fd_w);
			
    }
    }
    
    
    return 0;
}

-- ww.c

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

int main(int argc,char*argv[])
{
    if(argc<3)
    {
    	printf("格式输入有误!\n");
    	return -1;
    }
    

    char buff1[30] ={0};
    char buff2[30]={0};
    
    pid_t pid =fork();
    
    if(pid == 0){
    while(1){
    		int fd_w = open(argv[1],O_WRONLY);
			scanf("%s",buff1);
			write(fd_w,buff1,strlen(buff1));
			perror("write");
			close(fd_w);
		}
    }else if(pid > 0){
    	while(1){
    			int fd_r = open(argv[2],O_RDONLY);
				//sleep(2);
				int ret = read(fd_r,buff2,30);
				if(ret>0)
				{
					printf("接收到%d个字节\n",ret);
					printf("buff2:%s\n",buff2);
				}else {
					
					break;
				}
				memset(buff2,0,30);
				close(fd_r);
				
			}
    }
    
 	
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值