进程间通信 管道
在Linux中,管道是一种通信机制,用于将一个程序的输出直接连接到另一个程序的输入。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,它可以克服使用文件进行通信的两个问题,具体表现为限制管道的大小和读取进程可能工作得比写进程快。管道的思想是在内存中创建一个共享文件,从而使通信双方利用这个共享文件来传递信息。由于这种方式具有单向传递数据的特点,所以这个作为传递消息的共享文件就叫做“管道”。在管道的具体实现中,根据通信所使用的的文件是否具有名称,有“匿名管道”和“命名管道”。
匿名管道是一种具有亲缘关系的进程间的通信机制,它由创建它的进程及其子孙进程使用。匿名管道由pipe
函数创建并打开。
命名管道克服了匿名管道只能在具有亲缘关系进程间通信的缺点,使不具有亲缘关系的进程间也能通过命名管道进行通信。命名管道由mkfifo
函数创建。命名管道在文件系统中有对应的文件名。命名管道通过打开该文件名来打开管道,从而实现与其他进程的通信。
管道是连接两个进程的连接器(特殊文件)
匿名管道
当一个管道建立后,将获得两个文件描述符,分别用于对管道读取和写入,通常将其称为管道的读端和写端。
所用到的函数:
#include <unistd.h>
int pipe(int pipefd[2]);
参数说明:
pip
数组:存放两个文件描述符。
pipefd[0]
:存放管道读端文件描述符。pipefd[1]
:存放管道写端文件描述符。
返回值:
- 调用成功,返回
0
。 - 调用失败,返回
-
。
管道的读写操作
读规则
- 关闭管道的写端
close(fd[1]);
- 从管道读端
fd[0]
读出size
个字符放到buf
中
read(fd[0], buf, size);
- 读完关闭管道的读端
close(fd[0]);
写规则
- 关闭管道的读端
close(fd[0]);
- 把
buf
中的长度为size
的字符送到写端fd[1]
write(fd[1], buf, size);
- 写完关闭管道的写端
close(fd[1]);
例子:在父进程向管道内写入"Hello World\n",之后在子进程中读取内容。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
int fd[2];
int ret = pipe(fd);
char buf[100] = "Hello Wrold\n";
if(ret == -1) {
perror("pipe error");
exit(1);
}
pid_t pd = fork();
if(pd > 0) {
// 关闭读端
close(fd[0]);
// 用写端,写入内容
write(fd[1], buf, sizeof(buf));
close(fd[1]);
wait(NULL);
} else if(pd == 0) {
// 关闭写端
close(fd[1]);
// 从读端读取内容
read(fd[0], buf, sizeof(buf));
close(fd[0]);
write(STDOUT_FILENO, buf, sizeof(buf));
close(fd[0]);
}
}
命名管道
命名管道与匿名管道的区别:
- 匿名管道位于内存,只能用于有亲缘关系的进程通信
- 命名管道位于文件系统中,可以实现不同进程之间的通信
- 命名管道是一种双向通信管道,可以移动读/写模式打开
所用到的函数:
#include <sys/types.h>
#include <unistd.h>
int mkfifo(const char* pathname, mode_t mode);
参数说明:
pathname
:创建的FIFO
文件名mode
:规定FIFO
文件的读写权限
返回值:
- 成功时,返回
0
- 失败时,返回
-1
创建一个叫np
的命名管道
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
if(mkfifo("np", 0644) < 0) {
perror("Error!");
exit(1);
}
return 0;
}
向管道写入内容:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
pid_t fd;
// 指定文件的完整路径,如果文件不存在,将会创建
if ((fd = open("np", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
perror("error");
exit(-1);
}
printf("%d\n", fd);
char buf[] = "Hello World\n";
write(fd, buf, sizeof(buf));
close(fd);
printf("write success\n");
return 0;
}
读出内容:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
pid_t fd;
char buf[100];
if( (fd = open("np", O_RDONLY)) < 0) {
perror("Error\n");
exit(-1);
}
while( (read(fd, buf, sizeof(buf))) > 0) {
write(STDOUT_FILENO, buf, sizeof(buf));
}
return 0;
}