无名管道pipe(有血缘关系进程间的通信,fork创建)(179)
- 本质:1.内核创建的缓冲区(大小:4k),它是一个伪文件。
2.由两个文件描述符int pfp[2]引用,一个表示读端pfp[0],一个表示写端pfp[1]。
3.数据从写端流入管道,。从读端流出,它使用环形队列机制。 - 进程之间是不能相互访问的,,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷贝到内核缓冲区,进程2再从内核缓冲区把数据取走,内核提供的这种机制称为:进程间通信(IPC,interprocess communication)。
- 查看当前管道缓冲区的大小:ulimit -p
- 局限性:1.数据自己读不能自己写
2.不能反复读取数据
3.管道采用半双工通信方式,数据只能在一个方向上流动
4.只能在有公共祖先的进程间使用管道 - 管道内核通过什么方法实现:内核缓冲区,环形队列
管道进程的设计思路:
1.先利用pipe创建一个管道,此时返回两个文件描述符:pfp[0], pfp[1]。
2.为了创建有血缘关系的进程,利用fork创建子进程。
3.为了实现单向通信,▲父向子传数据:在子进程中关闭“写”(close(pfp[1])),在父进程中关闭“读”(close(pfp[0])),▲子向父传数据:在子进程中关闭“读”(close(pfp[0])),在父进程中关闭“写”(close(pfp[1]))。
#include<unistd.h>
int pipe(int pfp[2]);
成功:返回0,向pfp返回两个文件描述符,失败:返回-1.
使用管道完成进程间通信
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main()
{
int fd[2];
int pipeline = pipe(fd);
if(pipeline == -1)
{
perror("pipe error:");
exit(1);
}
pid_t pid;
pid = fork();
if(pid == -1)
{
perror("fork error:");
exit(1);
}
else if(pid == 0)
{
printf("I am child\n");
close(fd[1]);
char buf[1024];
int r = read(fd[0],buf,sizeof(buf));
if(r == 0)
{
printf("the content is empty\n");
}
else
{
write(STDOUT_FILENO,buf,r);
}
}
else
{
printf("I am father\n");
close(fd[0]);
write(fd[1],"666666\n",strlen("666666\n"));
}
return 0;
}
使用文件进行进程间通信
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fp,pid;
pid = fork();
char *buf = "666666\n";
if(pid == -1)
{
perror("fork error:");
exit(1);
}
else if(pid == 0)
{
printf("I am child\n");
fp = open("aaa",O_RDWR);
if(fp == -1)
{
perror("open error:");
exit(1);
}
else
{
int fd = read(fp,buf,sizeof(buf));
if(fd == 0)
{
printf("the content is empty\n");
}
else
{
write(STDOUT_FILENO,buf,fd);
}
}
}
else
{
printf("I am father\n");
int fp = open("aaa",O_RDWR);
if(fp == -1)
{
perror("open error:");
exit(1);
}
else
{
write(fp,buf,sizeof(buf));
}
}
return 0;
}
有名管道fifo(允许不相关进程间通信)
- 创建fifo文件:
1.在命令行创建文件:
mkfifo -m 644 file.fifo
2.在c文件中创建
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char*pathname,mode_t mode);
成功:返回又名管道的文件描述符,失败:返回-1
现今常用的进程间通信方式有:
1.管道:使用最简单(pipe),无名管道,所以进行通信的两个进程一定要有共同的祖先进程。
2.信号:开销最小
3.共享映射区:无血缘关系(mmap)
4.本地套接字:最稳定