进程间通信 之 管道
目录前言一、管道的核心概念1.1什么是管道1.2管道的两大类型二、有名管道1.优势2.有名管道来演示进程间通信3.有名管道的特点三、无名管道1.工作原理父子进程间通信2.无名管道来演示父子进程间通信3.无名管道的特点四、管道的优缺点1 .优点2.缺点前言管道是 UNIX 和类 UNIX 操作系统中最古老、最基本的进程间通信方式之一。它本质上是一个内核缓冲区以字节流的形式在进程间传递数据。一、管道的核心概念1.1什么是管道管道是一种半双工数据只能单向流动的通信机制。它连接一个进程的输出写入端和另一个进程的输入读取端就像现实中的水管连接两个容器一样。// 管道的本质两个文件描述符 int pipe_fd[2]; pipe(pipe_fd); // 创建管道 // pipe_fd[0] - 读端 // pipe_fd[1] - 写端1.2管道的两大类型类型特点适用场景示例命名管道有名管道有文件名可在任意进程间使用无亲缘关系的独立进程服务器-客户端通信匿名管道无名管道无文件名只能在有亲缘关系的进程间使用父子进程、兄弟进程通信ls | grep .txt二、有名管道1.优势有名管道通过文件系统中的一个特殊文件来标识解决了无名管道只能在亲缘进程间父子进程通信的限制。# 创建命名管道 mkfifo my_pipe # 或使用命令 mknod my_pipe p创建有名管道使用命令:mkfifo打开管道:open();关闭管道:close()读数据:read();写入数据:write();2.有名管道来演示进程间通信【思考】如果进程a要从键盘获取数据传递给另一个进程b,用已具备的知识思考如何完成?使用文件即可【问题】1.很慢. 2.读数据时不知道a什么时候会写入。代码实例写入端程序writer.c#include stdio.h #include stdlib.h #include fcntl.h #include sys/stat.h #include unistd.h #include string.h #define FIFO_NAME /tmp/my_fifo int main() { int fd; char message[] Hello through named pipe!; // 1. 创建命名管道如果不存在 mkfifo(FIFO_NAME, 0666); // 2. 打开管道写模式 // 注意open() 会阻塞直到有读端打开 fd open(FIFO_NAME, O_WRONLY); printf(Writer: Reader connected\n); // 3. 写入数据 write(fd, message, strlen(message) 1); printf(Writer: Message sent\n); // 4. 关闭管道 close(fd); return 0; }读取端程序reader.c#include stdio.h #include stdlib.h #include fcntl.h #include sys/stat.h #include unistd.h #define FIFO_NAME /tmp/my_fifo int main() { int fd; char buffer[100]; // 1. 打开管道读模式 // open() 会阻塞直到有写端打开 fd open(FIFO_NAME, O_RDONLY); printf(Reader: Writer connected\n); // 2. 读取数据 read(fd, buffer, sizeof(buffer)); printf(Reader: Received: %s\n, buffer); // 3. 关闭管道 close(fd); // 4. 删除管道文件 unlink(FIFO_NAME); return 0; }管道创建之后,它会在内存上分配一块空间.所以,管道的大小永远为0;3.有名管道的特点管道必须读,写进程同时open,否则会阻塞;如果管道没有数据,那么read会阻塞;管道的写端关闭,读read返回值为0;管道打开的时候只有只读和只写两种方式,读写方式打开是未定义的.三、无名管道1.工作原理父子进程间通信【核心机制】创建使用 pipe() 系统调用创建管道返回两个文件描述符。写入进程向fd[1] 写入数据。读取进程从fd[0] 读取数据。阻塞读空时阻塞写满时阻塞。2.无名管道来演示父子进程间通信代码示例#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include assert.h #include string.h int main() { int fd[2]; assert(pipe(fd)!-1); //fd[0] fd[1] pid_t pidfork(); assert(pid!-1); if(pid0) { close(fd[1]); char buff[128]{0}; read(fd[0],buff,127); printf(child read:%s\n,buff); close(fd[0]); } else { close(fd[0]); write(fd[1],hello,5); close(fd[1]); } exit(0); }3.无名管道的特点管道必须读,写进程同时open,否则会阻塞;如果管道没有数据,那么read会阻塞;管道的写端关闭,读read返回值为0;管道打开的时候只有只读和只写两种方式,读写方式打开是未定义的.无论有名还是无名,写入管道的数据都在内存中(管道的大小永远为0)管道是一种半双工通信方式(通信方式有单工,半双工,全双工)有名管道和无名管道的区别:有名管道可以在任意进程间使用,无名管道主要在父子进程间通信.管道的读端关闭,写会产生异常(发送信号SIGPIPE【注意】:读端关闭的描述符写端写入时产生该信号会终止程序(向无读进程的管道写数据)四、管道的优缺点1 .优点简单易用API 简单类似于文件操作自动同步阻塞机制自动处理同步问题无需锁机制内核保证 PIPE_BUF 内的写入是原子的亲缘关系友好父子进程通信特别方便2.缺点半双工数据只能单向流动某些系统提供全双工管道但不可移植无亲缘关系限制无名管道只能用于亲缘进程字节流没有消息边界需要应用层协议划分消息有限容量缓冲区大小有限通常为 4KB-64KB仅限本机不能用于网络通信
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2426761.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!