Linux——管道
目录
一、管道通信
1.1 管道通信定义
1.2 管道通信分类
1.3 管道通信特点
二、有名管道
2.1 单次管道通信
2.2 持续管道通信
三、无名管道
3.1 使用pipe创建管道
四、面试常考问题
4.1 进程间通信有哪些?
4.2 IPC机制有哪些?
4.3 有名管道和无名管道的区别?
4.4 写入管道的数据在哪里?
4.5 管道通信的方式?
4.6 单工、半双工、全双工是什么意思?
一、管道通信
1.1 管道通信定义
管道通信是指在计算机系统中,通过创建一个在两个进程之间传递数据的管道来进行进程间通信的方式。其中一个进程将数据写入到管道中,另一个进程则从管道中读取数据。管道通信可以实现进程之间的数据传输,常用于父子进程或者兄弟进程之间进行通信。管道通信通常实现在Unix和类Unix系统中。
1.2 管道通信分类
在Linux中,有多种类型的管道可以使用,其中最常见的包括命名管道(Named pipes)、匿名管道(Anonymous pipes)和进程间通信(Inter-process communication, IPC)管道。
-
命名管道(Named pipes):命名管道是一种在文件系统中创建的特殊文件,用于在不同进程之间进行通信。它通常使用mkfifo命令创建,可以像普通文件一样进行读写操作。
-
匿名管道(Anonymous pipes):匿名管道是一种临时的通信机制,用于在父进程和子进程之间进行通信。它通过pipe系统调用创建,只能在相关进程间进行通信。
-
进程间通信(Inter-process communication, IPC)管道:IPC管道是一种用于在不同进程之间进行通信的机制,可以通过管道、消息队列、共享内存等方式实现。在Linux中,IPC管道的实现比较复杂,需要使用一些特定的系统调用和库函数。
这些不同类型的管道都可以用来在Linux系统中进行进程间通信,选择适合的管道类型取决于具体的通信需求和场景。
1.3 管道通信特点
管道通信是一种进程间通信的机制,它具有以下特点:
-
半双工通信:管道是单向的,即数据只能在一个方向上流动,所以进程之间的通信是半双工的。
-
有限长度:管道的容量是有限的,一旦管道被填满,向管道写入数据的进程可能会被阻塞,直到管道中的数据被读取。
-
面向字节流:管道通信是面向字节流的,即数据在管道中是无边界的字节流,接收方需要根据协议或者约定来解析数据。
-
进程关系:通常情况下,管道通信是在具有亲缘关系的进程之间进行的,即父子进程或者兄弟进程之间。
总的来说,管道通信是一种简单而有效的进程间通信方式,适用于在具有亲缘关系的进程之间进行数据交换。
二、有名管道
有名管道(命名管道)fifo 单向命名管道通信:可以在任意两个进程间通信,但需要在同一个管道内。
管道为空:read会阻塞
管道为满:write会阻塞
2.1 单次管道通信
首先要创建管道
然后,a.c代码写入数据
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main()
{int fdw = open("fifo", O_WRONLY); // 以只写方式打开命名管道if (fdw == -1) {exit(1);}printf("fdw=%d\n", fdw);printf("input\n");char buff[128] = {0}; // 创建一个字符数组用于存储输入的数据fgets(buff, 128, stdin); // 从标准输入读取一行数据write(fdw, buff, strlen(buff)); // 将输入的数据写入到命名管道中close(fdw); // 关闭文件描述符exit(0); // 正常退出程序
}
最后,b.c代码用来读数据
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>int main()
{int fd = open("fifo",O_RDONLY);if(fd==-1){exit(1);}printf("fd=%d\n",fd);char buff[128]={0};int n = read(fd,buff,127);printf("buff:%s\n",buff);close(fd);exit(0);
}
运行结果:
必须打开两个窗口,一个执行写程序,另一个执行读程序
写入的数据会通过命名管道传输到读端程序,并被打印出来。
2.2 持续管道通信
写程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>int main()
{int fd=open("fifo",O_WRONLY);if(fd==-1){exit(1);}printf("fd=%d\n",fd); while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3) == 0){break;}write(fd,buff,strlen(buff));}close(fd);exit(0);
}
读程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>int main()
{int fd = open("fifo",O_RDONLY);if(fd==-1){exit(1);}printf("fd=%d\n",fd);while(1){char buff[128]={0};int n = read(fd,buff,127);if(n==0){break;}printf("buff:%s\n",buff);}close(fd);exit(0);
}
通过while循环就会一直通信
读端可以不断地从管道中读取数据,直到满足某个条件(如读取到特定结束标志)。
写端可以不断地向管道中写入数据,直到满足某个条件(如用户输入结束标志)
直至在写端./a中写入end才会关闭,终止程序。
三、无名管道
无名管道只能再父子进程间通信。它在内存中创建,没有在文件系统中的对应文件,因此被称为“无名”或“匿名”。
3.1 使用pipe创建管道
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>int main()
{int fd[2];if(pipe(fd) == -1)//创建无名管道,返回读和写的描述符{exit(1);}pid_t pid=fork();if(pid==-1){exit(1);}if(pid==0){close(fd[1]);char buff[128]={0};read(fd[0],buff,127);printf("buff=%s\n",buff);close(fd[0]);}else{close(fd[0]);write(fd[1],"hello",5);close(fd[1]);}exit(0);
}
四、面试常考问题
4.1 进程间通信有哪些?
管道、信号量、共享内存、消息队列、套接字
4.2 IPC机制有哪些?
常见的IPC机制包括:
-
管道(Pipe):管道是一种半双工的通信方式,可以在父进程与子进程之间进行通信。管道可以是匿名管道(Anonymous Pipe)或命名管道(Named Pipe)。
-
消息队列(Message Queue):消息队列是一种消息传递机制,进程可以发送消息到队列中,其他进程则可以从队列中获取消息。
-
信号量(Semaphore):信号量是一种用于实现进程间同步和互斥的机制,通过对信号量的操作来控制进程对共享资源的访问。
-
共享内存(Shared Memory):共享内存允许多个进程共享同一块内存区域,进程可以直接读写共享内存来进行通信。
-
套接字(Socket):套接字是一种网络通信机制,在同一台主机或不同主机上的进程之间进行通信。
-
信号(Signal):信号是一种异步的通信机制,进程可以发送信号给另一个进程以通知其发生了某个事件。
-
共享文件(Shared File):多个进程可以通过读写同一个文件来进行通信。
4.3 有名管道和无名管道的区别?
有名管道在任意两个进程间通信,而无名管道只能在父子进程间通信。
4.4 写入管道的数据在哪里?
写入管道的数据在内存中。
4.5 管道通信的方式?
半双工方式。
4.6 单工、半双工、全双工是什么意思?
单工、半双工和全双工是指通信系统中数据传输的方式和能力。
-
单工:单工通信只允许数据在一个方向上传输,不能同时进行双向传输。类似于广播电台,只能单向发送信息,接收者无法回复。
-
半双工:半双工通信可以在两个方向上传输数据,但不能同时进行。只能一个方向传输数据,要么是发送数据,要么是接收数据。类似于对讲机,一方说话时另一方只能听,不能同时说话。
-
全双工:全双工通信可以同时实现双向数据传输,允许发送和接收数据同时进行。类似于电话通话,两个人可以同时说话和听对方说话,实现双向交流。