【Linux进程间通信】三、FIFO命名管道
FIFO命名管道
1. 什么是FIFO
FIFO命名管道,也叫有名管道,来区分管道pipe。管道pipe只能用于有血缘关系的进程间通信,但通过FIFO可以实现不相关的进程之间交换数据。FIFO是Linux基础文件类型中的一种,但是FIFO文件在磁盘上没有数据块,仅仅用来标识内核中的一条通道。各进程可以打开这个文件进行read/write操作,实际上是在读写内核通道,这样就实现了进程间通信。
创建FIFO的方式:
- 使用命令创建:mkfifo 管道名,可以理解为创建一个管道伪文件。
- 使用库函数创建:mkfifo()函数,并且一旦使用mkfifo()创建了一个FIFO,就可以使用open来打开它,常见的文件I/O函数都可用于FIFO。如:close、read、write、unlink等。
实际上,创建一个FIFO命名管道的时候,内核会为FIFO(伪)文件开辟一个缓冲区,操作FIFO文件就相当于操作这个缓冲区,以此来实现进程间的通信,这种通信实际上就是文件读写的操作来实现的。(可以把FIFO理解为一个文件,一个进程向该文件写数据,另一个进程从该文件中读书数据,前提是两个进程读写的是同一个FIFO文件才能实现通信)
2. FIFO编程实战
示例: 使用FIFO实现进程间通信
创建两个进程,一个进程向FIFO写数据,一个进程从FIFO读数据。
/************************************************************
>File Name : write_fifo.c
>Author : Mindtechnist
>Company : Mindtechnist
>Create Time: 2022年05月21日 星期六 22时38分08秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("not fount fifoname\n");
return -1;
}
/*打开一个fifo文件*/
int fd = open(argv[1], O_WRONLY);
/*写FIFO文件*/
char buf[256];
int count = 1;
while(1)
{
memset(buf, 0, sizeof(buf));
/*循环写入*/
sprintf(buf, "count %04d", count++);
/*写入FIFO*/
write(fd, buf, strlen(buf));
sleep(1);
}
close(fd);
return 0;
}
/************************************************************
>File Name : read_fifo.c
>Author : Mindtechnist
>Company : Mindtechnist
>Create Time: 2022年05月22日 星期日 09时54分37秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("not found fifoname\n");
return -1;
}
int fd = open(argv[1], O_RDONLY);
char buf[256] = {0};
int ret;
while(1)
{
memset(buf, 0, sizeof(buf));
ret = read(fd, buf, sizeof(buf));
if(ret > 0)
{
printf("read buf: %s\n", buf);
}
}
close(fd);
return 0;
}
编译两个程序生成可执行文件,并使用命令mkfifo创建一个FIFO
测试的时候,我们在SecureCRT中克隆一个会话(相当于在Linux中打开两个shell终端),一个运行写进程,一个运行读进程。要注意的是,应该先运行写进程再运行读进程。
同时我们也可以打开多个进程去读写这同一个FIFO缓冲区,当多个进程去读的时候,被读进程1读走的数据就不会再被进程2读取了,比如说下面图中所示,这个进程读到的是36 38 40,而另一个进程读到的是37 39 41。(也可以开启多个写进程去写,读者可自行测试)
我们在读写FIFO的时候都使用了open()函数,使用open函数的时候有一个注意事项,使用open打开FIFO文件的时候,read端会阻塞等待write端open打开文件,直到write进程也使用open打开FIFO的时候,read进程中的open才会返回,反过来也是一样。我们可以在open函数的前后分别打印一句话来测试,只有读端写端都open了FIFO,第二个printf()语句才能打印。实际上只要有一个write和一个read打开了FIFO,就可以,不管是同一个进程还是多个进程。
printf("hello open...\n");
int fd = open(argv[1], O_WRONLY);
printf("bye open...\n");
附:Makefile
通过一个makefile编译多个程序
.PHONY:all clean
CC=gcc
CFLAGS=-Wall -g
EXE=write_fifo read_fifo
all:$(EXE)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
-@rm -f *.o $(EXE)