一、进程间通信的方式
进程间通信(IPC)主要有以下几种:
1.管道
2.FIFO
3.消息队列
4.共享内存
5.信号
6.信号量
7.套接字(socket)
二、管道
管道通常指无名管道,有以下特点:
①半双工,具有固定的读端和写端,数据只能单向流动,管道中的数据被读取就消失了。
②只能用于具有亲缘关系的进程之间的通信(父子进程、兄弟进程),若进程A关闭读端,进程B必须关闭写端。
③管道不是普通的文件,不属于其他任何文件系统,只存在于内存中。管道可以看成是特殊的文件,对它进行读写可以使用普通的read、write等函数。
④父子进程退出时,管道消失。
原理图:
函数原型:
#include <unistd.h>
int pipe(int pipefd[2]); //fd[0]为读端,fd[1]为写端
返回值:
成功:0
失败:-1
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd[2]; //文件描述符
pid_t pid;
char buf[128];
if(pipe(fd) == -1){
//创建管道
printf("pipe error!\n");
exit(-1);
}
pid = fork(); //创建子进程
if(pid == 0){
close(fd[1]); //关闭写端
read(fd[0],buf,128);
printf("message form Parent process: %s\n",buf);
}else if(pid > 0){
close(fd[0]); //关闭读端
write(fd[1],"hello!",6);
}else{
printf("fork error!\n");
exit(-1);
}
return 0;
}
二、FIFO
FIFIO,也称为命名管道,是一种文件类型。具有以下特点:
①FIFO 可以在无关的进程之间交换数据,与无名管道不同。
②FIFO 有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
③FIFO容量有限,进行数据读取是遵循“先进先出”。
函数原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
返回值:
成功:0
失败:-1
例子:
读端:fifo_read.c
#include <stdio.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
char buf[128];
//创建FIFO
if(mkfifo("./fifo",0600) == -1 && errno != EEXIST){
perror("error:");
}
//打开FIFO
fd = open("./fifo",O_RDONLY);
//接收消息
while(1){
read(fd,buf,128);
printf("message form write: %s\n",buf);
}
close(fd);
return 0;
}
写端:fifo_write.c
#include <stdio.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
//打开FIFO
fd = open("./fifo",O_WRONLY);
//发送消息
while(1){
write(fd,"hello!",6);
sleep(1);
}
close(fd);
return 0;
}
三、消息队列
消息队列就是存放消息的链表,存放在内核中。每个消息队列都有自己的标识符。消息队列具有以下特点:
①消息队列面向记录,其中的消息具有特定的格式和特定的优先级。
②消息队列独立于发送与接收进程。进程终止时,消息队列及其内容不会被删除。
③消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按照消息的类型读取。
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// 创建或打开消息队列:成功返回队列ID,失败返回-1
int ms