目录
一、认识管道
二、匿名管道
pipe函数
用法:
pipefd:
匿名管道通信:
三、命名管道
概念:
创建:
特性:
用途:
四、命名管道和匿名管道的区别
命名:
持久性:
进程间通信:
创建方式:
权限控制:
一、认识管道
将一个进程连接到另一个进程的数据量,我们称它为管道
在图片中who和wc是两个命令,运行后产生两个进程,who进程通过标准输出将数据送到管道中,wc进程再通过标准输入在管道中读取,数据传输完成。
who命令是查看当前云服务器的登陆用户,wc是统计当前行数
二、匿名管道
匿名管道是一种简单而有效的进程间通信方式,特别适用于父子进程之间或者相关进程之间的数据传输。
使用匿名管道实现父子进程间通信的原理就是,让两个父子进程先看到同一份被打开的文件资源,然后父子进程就可以对该文件进行写入或是读取操作,进而实现父子进程间通信。
注意:
- 管道方向:匿名管道是单向的,可以用于父子进程或兄弟进程之间的通信。如果需要双向通信,需要创建两个管道。
- 管道大小:匿名管道有固定的缓冲区大小。在写入管道时,如果写入的数据超过管道的容量,写入操作可能会阻塞或失败。因此,要确保在读取管道之前,已经将所有数据写入管道。
- 阻塞操作:管道的读取和写入操作默认是阻塞的,即如果没有可读数据或管道已满,写入和读取操作将阻塞进程。要避免阻塞,可以使用非阻塞的I/O操作或将管道设置为非阻塞模式。
- 进程间同步:如果多个进程同时读取或写入管道,可能会出现竞态条件。可以使用同步机制(如互斥锁或信号量)来确保进程之间的正确同步。
- 管道的生命周期:匿名管道在父进程和子进程之间共享,但在父进程终止后,子进程仍然可以继续使用管道。确保在不再需要管道时正确关闭它们,以避免资源泄漏。
pipe函数
pipe()
函数是一个在 Unix/Linux 系统中用于创建管道的系统调用。它创建一个管道,用于在两个相关的进程之间进行通信,其中一个进程作为管道的写入端,另一个进程作为管道的读取端。
用法:
#include <unistd.h>int pipe(int pipefd[2]);
pipefd:
在函数原型中,pipefd是一个整型数组,它有两个元素pipefd[0]表示管道的读取端、pipefd[1]表示管道的写入端。
- pipefd[0]:读取端是一个打开的文件描述符,用于从管道中读取数据。当管道中有数据可读时,对该文件描述符的读取操作将成功,否则读取操作将阻塞
- pipefd[1]:写入端是一个打开的文件描述符,用于向管道中写入数据。当管道的写入缓冲区未满时,对该文件描述符的写入操作将成功,否则写入操作将阻塞
(读取端):当进程从管道读取数据时,应该使用这个文件描述符。读取端是一个打开的文件描述符,用于从管道中读取数据。当管道中有数据可读时,对该文件描述符的读取操作将成功,否则读取操作将阻塞,直到有数据可读或者管道关闭。
匿名管道通信:
在创建匿名管道实现父子间通信需要fork()和pipe()搭配使用
1.父进程使用pipe创建管道
2.父进程创建子进程
父进程关闭写端,子进程关闭读端
- 管道只能够进行单向通信,因此当父进程创建完子进程后,需要确认父子进程谁读谁写,然后关闭相应的读写端。
- 从管道写端写入的数据会被存到内核缓冲,直到从管道的读端被读取。
三、命名管道
-
概念:
- 命名管道是一种特殊类型的文件,它允许不相关的进程之间进行通信。
- 与匿名管道不同,命名管道是由文件系统中的路径名标识的。
-
创建:
- 可以使用
mkfifo
命令在文件系统中创建命名管道。 - 也可以使用
mkfifo()
系统调用在程序中创建命名管道。
- 可以使用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main() {char *fifo_path = "/tmp/myfifo"; // 命名管道的路径名// 使用 mkfifo() 函数创建命名管道if (mkfifo(fifo_path, 0666) == -1) {perror("mkfifo");exit(EXIT_FAILURE);}printf("Named pipe created successfully at %s\n", fifo_path);return 0;
}
-
特性:
- 命名管道在文件系统中以文件的形式存在,但其行为类似于管道。
- 命名管道具有阻塞特性,当写入数据时,如果没有进程读取数据,则写入进程会被阻塞。
- 命名管道就是一种特殊类型的文件,两个进程通过命名管道的文件名打开同一个管道文件。
- 命名管道可以像普通文件一样设置权限,以控制哪些进程可以访问它。
- 进程通过向命名管道写入数据,然后由另一个进程从管道读取数据来进行通信。
- 多个进程可以同时向命名管道写入数据,但只有一个进程可以读取数据。
- 命名管道遵循文件系统的生命周期,可以通过删除其路径名来销毁管道。
-
用途:
- 命名管道常用于同一主机上的不同进程之间的通信,特别是当这些进程无法通过常规IPC(Inter-Process Communication)机制通信时。
- 它们可以在shell脚本中用作简单的IPC机制,允许不同的shell命令之间进行通信
- 命名管道通常用于本地进程间通信,因此不适用于远程进程通信
四、命名管道和匿名管道的区别
-
命名:
- 命名管道有一个在文件系统中的路径名,可以通过文件系统访问和识别。
- 匿名管道没有在文件系统中的路径名,只能在创建它的进程内部使用。
-
持久性:
- 命名管道是持久的,它们在文件系统中存在,直到被显式删除。
- 匿名管道是临时的,它们只存在于创建它们的进程的生命周期中,进程结束时管道会自动被销毁。
-
进程间通信:
- 命名管道允许不相关的进程之间进行通信,因为它们可以在文件系统中识别。
- 匿名管道只适用于具有父子关系的相关进程之间的通信,因为它们是通过
pipe()
系统调用创建的,并且没有在文件系统中的路径名。
-
创建方式:
- 命名管道可以使用
mkfifo
命令或mkfifo()
系统调用在文件系统中创建。 - 匿名管道可以使用
pipe()
系统调用在内存中创建,但它们不在文件系统中可见。
- 命名管道可以使用
-
权限控制:
- 命名管道可以像普通文件一样设置权限,以控制哪些进程可以访问它。
- 匿名管道没有权限控制,只能由创建它的进程和其子进程访问。
总的来说,命名管道和匿名管道都是进程间通信的方式,但它们的持久性、适用范围和创建方式有所不同。如果需要在不相关的进程之间进行通信,并且需要持久性,则可以选择命名管道;如果只需要在相关进程之间进行临时通信,则可以选择匿名管道。