当从一个进程连接数据流到另一个进程时,我们使用属于管道(pipe)。我们通常是把一个进程的输出通过管道连接到另一个进程的输入。
(管道是在内存上
开辟出一块空间,不被任何其他进程所占用的)管道包括全双工通讯和半双工通讯。
管道原理:
管道操作:
有名管道:应用于任意两个进程之间数据的单向传递
创建:命令方式(mkfifo)、函数方式(mkfifo)
打开:open
写数据:write
读数据:read
关闭:close
有名管道是在文件目录树中有一个文件标识(管道文件),实际不占用磁盘空间,数据缓存在内存中。
与通过 pipe 调用创建管道不同,FIFO 是以命名文件的形式存在, 而不是打开的文件描述符,所以在对它进行读写操作之前必须先打开它。FIFO 也用 open 和 close 函数打开和关闭,这与我们的对文件的操作一样,但它多了一些其他功能,对 FIFO 来说, 传递给 open 调用的是 FIFO 的路径名, 而不是一个正常的文件。
阻塞运行函数:函数调用后并不会立即返回,需要等待某些条件的发生才会返回,open 操作管道文件时,阻塞运行的函数。
如果一个进程以只写方式打开一个管道文件,open 会阻塞运行,直到有一个进程以读的方式打开这个管道文件,open 才会返回,进程才会接着执行。
如果一个进程以只读方式打开一个管道文件,open 会阻塞运行,直到有一个进程以写的方式打开这个管道文件,open 才会返回,进程才会接着执行。
read 函数也会阻塞运行, 直到写端写入数据或所有写端关闭时返回。
read 读取数据并且会将内存上的已读数据清空。
练习:A进程负责循环接受用户输入的数据,以“end”为结束标志,B进程负责统计用户输入的单词的个数,显示到界面上。
首先利用 mkfifo FIFO 命令创建管道文件“FIFO”,如图所示:
A进程代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
int main()
{
int fd = open("FIFO", O_WRONLY);
assert(fd != -1);
if (fd == -1)
{
exit(0);
}
char buffer[128] = {0};
printf("Please input:");
fgets(buffer, 128, stdin);
while (strncmp(buffer,"end",3) != 0)
{
write(fd, buffer, strlen(buffer)-1);
memset(buffer, 0, 128);
fgets(buffer, 128, stdin);
}
close(fd);
return 0;
}
B进程代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
int main()
{
int fd = open("FIFO", O_RDONLY);
assert(fd != -1);
if (fd == -1)
{
exit(0);
}
char buffer[128] = {0};
int count = 0;
while (read(fd,buffer,127) > 0)
{
printf("%s\n", buffer);
count++;
}
printf("count: %d\n",count);
close(fd);
return 0;
}
测试运行结果如图所示: