进程间通信方式(一)-- 无名管道、有名管道
文章目录
- 1. 进程间通信方式分类
- 2. 进程间通信实现方式
- 3. 无名管道
- 3.1 概念
- 3.2 相关函数
- 读写规律
- 3.3 无名管道实现进程间通信
- 4. 有名管道
- 4.1 概念
- 4.2 创建有名管道
- 读写规律
- 4.3 一个进程只读,一个进程只写
1. 进程间通信方式分类
一共七类
早期的进程间通信方式:
- 无名管道、有名管道、信号通信
SYSEM V: (IPC对象)
- 消息队列、共享内存、信号灯集
BSD:
- 套接字通信
共享内存是所有进程间通信方式中效率最高的,因为它直接操作物理内存
信号通信是进程间通信方式中唯一的异步通信机制
无名管道、有名管道、信号通信、消息队列、共享内存、信号灯集,这6种通信方式只能实现一台主机的多个进程间通信
套接字可以实现不同主机间多个进程的通信
2. 进程间通信实现方式
任何一个进程在开启或者创建之后,系统都会分配4G虚拟空间,包含1G内核空间和3G用户空间,用户空间是当前进程私有的,而内核空间是一个操作系统中所有进程所公有的,所以进程间通信机制的本质就是在内核空间开辟区域,多个进程同时对同一个开辟的区域操作,从而实现进程间的通信
所以这七种进程间通信方式基本都是在学习如何在内核空间开辟区域,然后如何操作的问题
3. 无名管道
3.1 概念
无名管道就是在内核空间开辟一块区域,然后会给进程两个文件描述符,只要多个进程可以得到这两个文件描述符,就可以对同一个管道进行操作
无名管道是一个半双工的通信方式,意味着有固定的读端和写端
无名管道只能用于具有亲缘关系的进程间通信,原因是因为无名管道既然给当前进程的是两个文件描述符,那么这两个文件描述符的创建只能在当前进程的用户空间,当fork之后产生的进程,会继承原本父进程的所有的空间,所以他能得到这两个文件描述符及对应的文件表项(struct file
)
3.2 相关函数
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个无名管道
参数:pipefd:保存两个文件描述符的数组pipefd[0] 用于读操作pipefd[1] 用于写操作
返回值:成功:0失败:-1//注意:管道无法使用lseek改变文件的偏移量
// if(lseek(pipefd[0], 10, SEEK_SET) == -1)
// {// perror("lseek error");
// exit(1);
// }
读写规律
读写段 | 读操作 | 写操作 | 现象 |
---|---|---|---|
读写段都存在 | 只读 | - | 管道中有数据,则正常读取;无数据会阻塞 |
读写段存在 | - | 只写 | 一直向管道中写数据,直到管道满(默认无名管道为64kBytes) |
关闭写段,只有读端 | 只读 | - |
如果管道中有数据,则正常读取;如果管道中没有数据,读操作返回0
|
关闭读段,只有写端 | - | 只写 | 当执行第一个写操作时,当前系统中会产生一个信号SIGPIPE,这个信号的名字称之为管道破裂,这个信号默认对当前进程的处理是结束进程 |
3.3 无名管道实现进程间通信
由于无名管道是通过调用函数直接给当前进程两个文件描述符,所以没关系的进程无法获得相同的两个文件描述符,所以只有使用fork之后创建的进程才可以继承这两个文件描述符,所以无名管道只能使用在具有亲缘关系的进程间通信
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{int pipefd[2];if(pipe(pipefd) == -1){perror("pipe error");exit(1);}pid_t pid;if((pid = fork()) == -1){perror("fork error");exit(1);}else if(pid > 0) //父进程负责发送数据{char buf[32] = {0};while(1){fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';write(pipefd[1], buf, sizeof(buf));}}else //子进程负责接收数据{char buf[32] = {0};while(1){memset(buf, 0, sizeof(buf));read(pipefd[0], buf, sizeof(buf));printf("from parent: %s\n", buf);}}return 0;
}
4. 有名管道
4.1 概念
有名管道创建好之后会在本地创建一个管道文件,对于当前系统中的进程都是可见的,所以有名管道可以实现不相关进程间通信,由于创建了一个文件,所以对文件操作本质就是对内核开辟的区域操作,通过文件IO就可以操作
4.2 创建有名管道
方法1:使用shell命令创建有名管道mkfifo 文件名system("mkfifo myfifo");方法2:使用函数创建有名管道#include <sys/types.h>#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);功能:创建一个有名管道参数:pathname:管道文件名mode:文件权限,一般0664返回值:成功:0失败:-1#define FIFONAME "myfifo"if(mkfifo(FIFONAME, 0664) == -1){//如果管道文件已经存在,则不做任何处理,直接操作即可,所以不需要退出if(errno != EEXIST){perror("mkfifo error");exit(1);}}//打开管道文件int fd;if((fd = open(FIFONAME, O_RDWR)) == -1){perror("open error");exit(1);}
注意管道文件只是起到标识作用,标识在内核空间里面开辟的区域,不管向管道文件中写多少数据,本质都是向内核空间写数据,所以管道文件永远0个字节
一旦将数据从管道中读取出来,原本管道中会删除读取的数据
读写规律
读写段 | 读端 | 写端 | 现象 |
---|---|---|---|
读写段都存在 | 只读 | - | 如果管道中有数据,正常读数据;如果没有数据,则阻塞 |
读写段都存在 | - | 只写 | 正常写,当写满时阻塞。(默认有名管道64kBytes) |
关闭写端,只有读端 | 只读 | - |
在open() 阻塞
|
关闭读端,只有写端 | - | 只写 |
在open() 阻塞
|
不同进程打开同一有名管道 | 一个进程读 | 一个进程写 |
两个进程都不会在open() 阻塞;在运行过程中如果写操作的进程结束,读操作进程中read 函数会返回0 ;如果读操作的进程结束,写操作进程中一旦运行write 函数就会产生SIGPIPE 信号,默认会让当前进程结束
|
4.3 一个进程只读,一个进程只写
实际使用时,最好保证打开管道文件时可读可写权限都有
read.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>#define FIFONAME "myfifo"int main(int argc, char const *argv[])
{if(mkfifo(FIFONAME, 0664) == -1){//如果管道文件已经存在,则不做任何处理,直接操作即可,所以不需要退出if(errno != EEXIST){perror("mkfifo error");exit(1);}}int fd;if((fd = open(FIFONAME, O_RDONLY)) == -1){perror("open error");exit(1);}puts("****************");ssize_t bytes;char buf[32] = {0};while(1){if((bytes = read(fd, buf, 32)) == -1){perror("read error");exit(1);}printf("bytes = %ld, buf = %s\n", bytes, buf);}return 0;
}
write.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>#define FIFONAME "myfifo"int main(int argc, char const *argv[])
{if(mkfifo(FIFONAME, 0664) == -1){//如果管道文件已经存在,则不做任何处理,直接操作即可,所以不需要退出if(errno != EEXIST){perror("mkfifo error");exit(1);}}int fd;if((fd = open(FIFONAME, O_WRONLY)) == -1){perror("open error");exit(1);}puts("****************");char buf[32] = {0};while(1){fgets(buf, 32, stdin);buf[strlen(buf) - 1] = '\0';write(fd, buf, 32);}return 0;
}
进程间通信方式(一)-- 无名管道、有名管道相关推荐
- linux 进程间通信及makefile 无名管道/有名管道/共享内存/信号/消息队列
http://www.voidcn.com/article/p-hxvuiypm-mr.html https://www.cnblogs.com/wuyida/archive/2013/02/03/6 ...
- 6.进程通信 无名管道 有名管道
进程间通信(IPC,InterProcess Communication) 概念:就是进程和进程之间交换信息. 常用通信方式 无名管道(pipe) 有名管道 (fifo) 信号(signal) 共享内 ...
- 无名(有名)管道,读写文件内容范例
一,无名管道传输范例 编写之前,我们需要确定从写入至写出需要open的内容,包含管道读端,写端,文件1,文件2.这里我们引用main函数中的参数,argv[].从命令行进行读写. 本次编写无名管道操作 ...
- 【Linux】管道文件(有名管道、无名管道)
[Linux]管道文件(有名管道.无名管道) 多进程编程的目的就是为了同时完成多个任务. 例如:一个产品,一个软件,需要n个进程同时执行才能完成,而这些进程之间一定是有所联系的. 因此:多进程工作时, ...
- Linux有名管道与无名管道简介
无名管道 无名管道是最古老的进程通信方式, 有如下两个特点: 1. 只能用于有关联的进程间数据交互, 如父子进程, 兄弟进程, 子孙进程, 在目录中看不到文件节点, 读写文件描述符存在一个 int 型 ...
- linux有名管道 mkfifo,有名管道mkfifo
int mkfifo(const char *pathname, mode_t mode); int mknod(const char *pathname, mode_t mode, dev_t de ...
- 61-Linux_管道_有名管道
文章目录 管道 1.有名管道 (1)创建有名管道 (2)有名管道演示进程间通信 管道 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递.调用pipe系统函数即可创建一个管道.有如 ...
- linux进程间通讯-有名管道
文章目录 阻塞和非阻塞概念 通过fcntl函数设置文件的阻塞特性 文件描述符概述 文件描述符的复制 有名管道 有名管道的创建 有名管道的基本读写操作 有名管道实现进程间通信 有名管道的读写规律(阻塞) ...
- 有名管道----mkfifo函数的使用
有名管道----mkfifo函数的使用 有名管道 mkfifo函数介绍 mkfifo函数使用 有名管道 有名管道可以在任意两个进程之间通信,而无名管道只能在父子进程之间进行通信.此外,有名管道可以 ...
最新文章
- Vue 框架-02-事件:点击, 双击事件,鼠标移上事件
- 湖北师范大学c语言考试题目,湖北师范学院2010期末C语言试卷.doc
- Python异常捕获及自定义异常类
- #ifndef#define与namespace杂谈
- 送给那些有代码基础但仍旧不会学自动化测试的朋友们
- Unity中实现解析XML文件
- matlab2016 wavread,matlabwavread用法
- win10右键文件夹转圈卡死
- 手机里面android什么意思,wipe什么意思?安卓手机如何wipe
- 删除linux终端的历史命令,清除Linux终端命令的历史记录
- 深度学习常用算子(一)
- 【报告分享】2021年快手母婴行业数据价值报告-磁力引擎(附下载)
- 【模拟经营】《模拟城市4豪华版》免安装中文版
- A-Level商务例题解析及练习
- meta20 无法安装 google play_不ROOT不刷机,小米手机如何安装谷歌 GMS 三件套
- 准备注册网易企业邮箱,安全功能怎么样?
- 在Golang里如何实现结构体成员指针到结构体自身指针的转换
- STM32精英版(正点原子STM32F103ZET6开发板)学习篇13——ssd1306OLED实验
- hdu 1535 Invitation Cards
- echart 图表类型