进程间通信的5中方式:
有名管道,匿名管道,systemv,posix消息队列,信号量,文件共享映射,
注意,5种进程间通信均操作的内核空间
首先我们来浅谈下匿名管道pipe
匿名管道是通过环形队列实现的,可实现节省空间和避免溢出等问题。
匿名管道有两个特点,一个是方向性,另一个是具有流向
匿名管道只能解决父子进程之间的通信,一般使用pipe时在fork之前进行
匿名管道一共四个文件描述符,两个读,两个写,分别指向管道的两端,而只有这四个文件描述符全部关闭,管道才可以被销毁
![](https://i-blog.csdnimg.cn/blog_migrate/930510284caed8bac159039853451eae.jpeg)
匿名管道的特点:1.只支持单项数据流
2.只有父子进程可通信
3.没有名字
4.管道缓冲区是有限的
5.管道所传送的是无格式字节流,这就要求读出方和写入方约定好格式,比如多少字节算一个消息。
匿名管道的API pipe(int fd[2])如果成功,则在内存中开辟内核缓冲区,并将管道的读端和写端连通
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#define MSG "Test Message...."
int main(void)
{
int fds[2];
pid_t pid;
//父进程创建管道
pipe(fds);
//创建子进程
pid = fork();
//确定通信方向:父写子读,关闭无用文件描述符
if(pid > 0){
close(fds[0]);
printf("Parent pid:%d\n",getpid());
sleep(5);
printf("parent send msg:%s\n",MSG);
write(fds[1],MSG,strlen(MSG));
close(fds[1]);
while(1);
}else if(pid == 0){
char buf[1024];
int len;
int flags;
close(fds[1]);
printf("Child pid:%d\n",getpid());
flags = fcntl(fds[0],F_GETFL);
flags|=O_NONBLOCK;
fcntl(fds[0],F_SETFL,flags);//改变管道的非阻塞属性
tryagain:
len = read(fds[0],buf,sizeof(buf));
if(len == -1){
if(errno == EAGAIN){
printf("child read kernerl buf tryagain....\n");
sleep(1);
goto tryagain;
}
}
printf("Child recv msg:\n");
write(STDOUT_FILENO,buf,len);
close(fds[0]);
}else{
perror("fork error:");
exit(0);
}
return 0;
}