目录
system v IPC对象 共享内存、消息队列、信号灯集
原理
1、创建key值
功能
参数
2、共享内存
申请一块共享内存
功能
参数
返回值:
注意
查看IPC对象
删除IPC对象
共享内存映射
功能
参数
返回值
撤销共享内存映射
返回值
删除共享内存
功能
进程间通信小结
同主机内
传统的进程间通信方式
管道
信号
system V 进程间通信方式
不同主机
socket
system v IPC对象 共享内存、消息队列、信号灯集
原理
- 进程都是通过IPC对象唯一的名字,称为键key,
- 找到IPC对象,但内核还是通过IPC对象的ID来找到它.
- 不同进程只要获得同一IPC对象的键key,
- 就可以实现操作同一IPC对象,从而实际进程间通信

进程a和进程b能实现通信是因为:它们通过一个key值,来找到共享内存的id号

在System V(系统5)通信中,第一步先创建一个key值,只要创建方式一样,就是同一个key值;第二步建立key值和IPC之间对应的关系;第三步,结合对应IPC对象的操作逻辑实现操作,最终用完之后销毁。
1、创建key值
key_t ftok(const char* pathname,int proj_id);
功能
- 获得key值
参数
- pathname:一个已经存在的文件路径(避免传".")
- proj_id:只会使用它的低八位
例:key_t key = ftok("/home/will/",'i');
2、共享内存
共享内存效率高是因为它直接使用一块内核空间
申请一块共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能
- 申请一块指定大小共享内存
参数
key
获得key方法
- IPC_PRIVATE : 在亲缘间进程通信使用
- ftok()函数获得key :可用于非亲缘关系的进程间
size
- 申请的大小,(分配的实际大小是4K的倍数,但可用的大小为申请大小)
shmflg
- IPC_CREAT | 0666 对应的共享内存段不存在,则创建, 存在直接返回ID
- IPC_CREAT | IPC_EXCL | 0666
- 如果对应的共享内存段已经存在,此时shmget调用失败,错误码设为EEXIST
返回值:
- 成功返回共享内存id;失败返回-1
注意
- 当key值对应的共享内存ID不存在,此时会申请一块新的共享内存区域
- 当key值对应的共享内存ID存在,此时直接返回已经存在的共享内存ID
查看IPC对象
ipcs -m/-q/-s
删除IPC对象
ipcrm -m/-q/-s ID
-m:memory
-q:queue
-s:semaphore
练习:探测共享内存是否存在,如果存在,报错,如果不存在,则创建
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
//1.创建key值
key_t key = ftok("/",'A');
if(key < 0)
{
perror("ftok fail");
return -1;
}
printf("key:%#x\\n",key);
//2.shmget:创建共享内存对象并建立和key关系
int shmid = 0;
if((shmid = shmget(key,1024,IPC_CREAT|IPC_EXCL|0666))<0)
{
perror("shmget fail");
return -1;
}
printf("id:%d\\n",shmid);
return 0;
}
共享内存映射
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能
- 映射共享内存到进程的私有地址空间
参数
shmid 共享内存段的标识
shmaddr NULL 让系统自动完成映射
shmflg 0 映射可以读写;
SHM_RDONLY 映射后只能读
返回值
- 成功返回映射后的地址
- 失败返回 (void *)-1,并置errno
注意:进程结束,映射自动撤销
撤销共享内存映射
int shmdt(const void *shmaddr);
返回值
- 成功返回0
- 失败返回-1,并置errno
注意给shmdt传的地址必须是shmat获得的!
删除共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能
- 对共享内存进行控制
- 若cmd参数设置为IPC_RMID,可实现删除共享内存
注意:删除共享内存并不是只要有进程删除就立刻删除,而是当映射次数为0时才会真正删除。
例:删除共享内存
shmctl(shmid,IPC_RMID,NULL);
write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
//1.创建key值
key_t key = ftok("/",'A');
if(key < 0)
{
perror("ftok fail");
return -1;
}
printf("key:%#x\\n",key);
//2.shmget:创建共享内存对象并建立和key关系
int shmid = 0;
if((shmid = shmget(key,1024,IPC_CREAT|0666))<0)
{
perror("shmget fail");
return -1;
}
printf("id:%d\\n",shmid);
//3.映射共享内存
int* p=shmat(shmid,NULL,0);
if(p == (void*)-1)
{
perror("shmat fail");
return -1;
}
//4.已经获得一块可使用的内存空间
*p = 100;
//5.解除映射
if(shmdt(p) < 0)
{
perror("shmdt fail");
return -1;
}
//6.删除共享内存
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
//1.创建key值
key_t key = ftok("/",'A');
if(key < 0)
{
perror("ftok fail");
return -1;
}
printf("key:%#x\\n",key);
//2.shmget:创建共享内存对象并建立和key关系
int shmid = 0;
if((shmid = shmget(key,1024,IPC_CREAT|0666))<0)
{
perror("shmget fail");
return -1;
}
printf("id:%d\\n",shmid);
//3.映射共享内存
int* p=shmat(shmid,NULL,0);
if(p == (void*)-1)
{
perror("shmat fail");
return -1;
}
//4.已经获得一块可使用的内存空间
printf("*p:%d\\n",*p);
//5.解除映射
if(shmdt(p) < 0)
{
perror("shmdt fail");
return -1;
}
//6.删除共享内存
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
进程间通信小结
同主机内
传统的进程间通信方式
管道
- 无名管道———亲缘关系 pipe
- 有名管道———亲缘/非亲缘(任意进程) mkfifo
信号
- 软中断
- siganal
- kill
- pause
system V 进程间通信方式
- 共享内存:ftok shmget shmat shmdt shmctl
- 消息队列
- 信号量集
不同主机
socket
套接字




