一、基本概念
- 什么是进程间通信:是指两个或多个进程之间交互数据的过程,因为进程之间是相互独立的,为了进程间协同工作就必须实现进程间交互数据
进程间通信的分类:
- 简单的进程间通信:信号、普通文件、环境变量表、命令行参数
- 传统的进程间通信:管道文件
- XSI的进程间通信: 共享内存、消息队列、信号量
- 网络进程间通信:Socket套接字
二、传统的进程间通信-管道文件
- 管道是UNIX系统中最古老的进程间通信技术,古老意味着所有系统都支持,早期的管道是半双工通信,现有的系统管道是全双工通信
- 管道就是一种特殊的文件,数据在文件中是流动的,读取之后就自动消失,如果文件中没有数据则会阻塞
有名管道:基于有文件名的管道文件的通信
编程模型
进程A 进程B
创建管道
打开管道 打开管道
写数据 读数据
关闭管道 关闭管道
删除管道
创建有名管道文件:
1、命令 mkfifo
2、函数
int mkfifo(const char *pathname,mode_t mode);
功能:创建有名管道
pathname:管道文件路径
mode:管道文件权限 0664
管道A
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,const char* argv[])
{
// 创建管道文件
if(mkfifo("fifo",0664))
{
perror("mkfifo");
return -1;
}
// 打开
int fd = open("fifo",O_WRONLY);
if(0 > fd)
{
perror("open");
unlink("fifo");
return -1;
}
// 写数据
char buf[256] = {};
for(;;)
{
printf(">>>");
scanf("%s",buf);
write(fd,buf,strlen(buf)+1);
if(0 == strcmp(buf,"quit"))
{
printf("通信结束!\n");
break;
}
}
// 关闭删除
close(fd);
usleep(1000);
unlink("fifo");
}
管道B
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,const char* argv[])
{
// 打开
int fd = open("fifo",O_RDONLY);
if(0 > fd)
{
perror("open");
return -1;
}
// 读数据
char buf[256] = {};
for(;;)
{
read(fd,buf,sizeof(buf));
printf("read:%s\n",buf);
if(0 == strcmp(buf,"quit"))
{
printf("通信结束!\n");
break;
}
}
// 关闭
close(fd);
}
匿名管道:只适合通过fork创建父子进程之间使用
int pipe(int pipefd[2]);
功能:创建一个匿名管道文件
通过pipefd返回该匿名管道文件的读权限fd和写权限的fd
pipefd[0] 用于读匿名管道
pipefd[1] 用于写匿名管道
编程模型:
父进程 子进程
获取一对fd
创建子进程 拷贝\共享一对fd
关闭读 关闭写
写数据 读数据
关闭写 关闭读
三、XSI进程间通信
X/open公司制定的用于进程间通信的系统(S)接口(I)
XSI进程间通信都需要借助系统内核完成,需要创建内核对象,内核对象会以整数形式返回给用户态,类似于文件描述符,也叫做IPC标识符
文件的创建打开需要借助文件名,IPC内核对象需要借助IPC键值(整数),必须要确保IPC键值是独一无二的
key_t ftok(const char *pathname, int proj_id);
功能:计算出一个独一无二的IPC键值
pathname:项目路径
proj_id:项目标号
返回值:计算出来的IPC键值
注意:项目路径必须真实存在,否则计算出来的key永远相同
共享内存:
基础特点:
两个或多个进程之间共享一块由内核负责统一管理内存,该内存可以与多个进程的虚拟内存进行映射
int shmget(key_t key,size_t size,int shmflg);
功能:创建\获取一块共享内存
key:IPC键值
size:共享内存的大小,获取共享内存时此参数无意义,一般给0
shmflg:
IPC_CREAT 创建共享内存,如已存在直接获取
IPC_EXCL 共享内存已存在,返回失败
获取时直接给0
注意:如果是创建共享内存还需要额外提供共享内存的权限 例如:IPC_CREAT|0664
返回值:IPC标识符,失败-1
void *shmat(int shmid,const void *shmaddr, int shmflg);
功能:让虚拟内存与共享内存进行映射
shmid:IPC标识符 shmget的返回值
shmaddr:想要映射的虚拟内存首地址,为NULL时系统会自动分配地址
shmflg:
SHM_RDONLY 以只读方式映射共享内存
SHM_RND:只有shmaddr参数不为NULL时才有有效,表示从shmaddr开始向下以整数页方式映射
返回值:与共享内存映射成功后的虚拟内存首地址,失败返回(void *) -1
int shmdt(const void *shmaddr);
功能:取消映射
shmaddr:映射成功后的虚拟内存首地址
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
功能:删除/控制共享内存
shmid:IPC标识符
cmd:
IPC_STAT 获取共享内存属性 buf输出型参数
IPC_SET 设置共享内存属性 buf输入型参数
IPC_RMID 删除共享内存 NULL
buf
编程模型:
进程A 进程B
创建共享内存 获取共享内存
映射共享内存 映射共享内存
写数据并通知其他进程 收到通知并读数据
收到通知并读数据 写数据并通知其他进程
取消映射 取消映射
删除共享内存