system V IPC
IPC : Inter-Process Communication (进程间通讯)
System V IPC 对象共有三种:
- 消息队列
- 共享内存
- 信号量
System V IPC 是由内核维护的若干个对象,通过ipcs命名查询
- 每个 IPC 对象都有一个唯一的 ID,可以通过ftok()函数生成
1.重点!重点!重点 ftok函数:
1.函数头文件
#include<sys/types.h>
#include<sys/ipc.h>
2.函数原型
key_tftok(const char*pathname,int proj_id);
3.函数参数
pathname:路径名(文件的inode节点号)//随便取,但必须要是文件存在
proj_id: 8bit的proj_id整数//随便取,但最好取128以内数字
4.函数返回值
成功:返回合成的key
失败:-1,并设置errno
2.消息队列:
2. 1消息队列的简介
- 消息队列就是一个消息的列表,进程可以在消息队列中添加消息和的读取消息
- 消息队列具有FIFO的特性,具有无名管道与有名管道各自的优势,可以支持任意两个进程的进程间通讯
消息队列是属于 Sytem V IPC 的一种,由内核维护与管理,通过 ipcs -q 查看
2.2 创建消息队列:
创建消息队列是时调用msgget 函数
1.函数头文件
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
2.函数原型
int msgget(key_t key,int msgflg);
3.函数参数
key:由ftok函数合成
msgflg:消息队列标志
IPC_CREAT创建标志
IPC_EXCL(权限控制标志) 如果消息队列存在,则报错,errno设置为EEXIST
4.函数返回值
成功:返回消息队列id
失败:返回-1,并设置errno
注意!注意! 注意! 创建消息队列用的最多的方式是:
int ret = msgget(key, 0644 | IPC_CREAT);
//这是创建消息队列最常见的格式 0644代表权限,key代表键值;
2.3 发送消息和接受消息函数
发送消息函数 msgsnd:
1.函数头文件
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
2.函数原型
int msgsnd(int msqid,const void* msgp,size_t msgsz,int msgflg);
3.函数参数:
msqid:消息队列ID
msgp:消息结构体指针
msgsz:消息内容的长度
msgflg:消息队列标志,默认可以填0,IPC_NOWAIT,可以设置非阻塞//最常用的是0
4.函数返回值
成功:返回0
失败:-1,并设置errno
接收消息函数 msgrcv :
1.函数头文件
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
2.函数原型
ssize_t msgrcv(int msqid,void* msgp,size_t msgsz,long msgtyp,int msgflg);
3.函数参数
msqid:消息队列id
msgp:消息结构指针
msgsz:最大读取的字节数
msgtyp:消息类型
msgflg:消息队列标志,默认可以填0,IPC_NOWAIT,可以设置非阻塞
4.函数返回值:
成功:返回实际读取消息内容的字节数
失败:-1,并设置errno
2.4 删除消息队列函数
删除消息队列需要调用 msgctl函数:
1.函数头文件
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
2.函数原型
int msgctl(int msqid,int cmd,struct msqid_ds*buf);
3.函数参数:
msqid:消息队列id
cmd:命令字
IPC_STAT:获取消息队列属性
IPC_SET:设置消息队列属性
IPC_RMID:删除消息队列,用此命名时,第三个参数为NULL
buf:消息队列属性结构体对象指针
函数返回值
成功:IPC_STAT,IPC_SET,and IPC_RMID 返回0
失败:返回-1,并设置errno
重点 !重点 !重点!:
删除消息队列的固定格式是:
int ret = msgctl(msqid,IPC_RMID,NULL)//msqid 为消息队列编号,
//这是删除消息队列固定格式
2.5 测试实例(cpp代码):
using namespace std;
#include <iostream>
#include <string.h>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <strings.h>
#define PATH "/mnt/hgfs"
#define PRO_ID 78
#define SIZE 128
#define MTYPE1 10
#define MTYPE2 20
//此题目标,创造两个子进程,并用父进程给他们发消息
typedef struct msg{
long mtype;
char mtext[SIZE];
}MSGBUF;
int main(){
key_t key = ftok(PATH,PRO_ID);
if(key == -1){
cout << "create key fail" << endl;
exit(EXIT_FAILURE);
}
pid_t pid1 = fork();
if(pid1 == -1){
cout << "create pid1 failed" << endl;
exit(EXIT_FAILURE);
}else if(pid1 == 0){
sleep(2);
int rmisgid1 = msgget(key,IPC_CREAT | 0644);
if(rmisgid1 == -1){
cout << "rmisgid1 failed" << endl;
exit(EXIT_FAILURE);
}
MSGBUF sbuf1;
//清空sbuf1里的东西
bzero(&sbuf1,sizeof(sbuf1));
ssize_t rtypes = msgrcv(rmisgid1,&sbuf1,SIZE,MTYPE1,0);
if(rtypes == -1){
cout << "rtypes false"<< endl;
exit(EXIT_FAILURE);
}
cout << "rmisgid1接受到的消息是:";
printf("%s\n",sbuf1.mtext);
}else if(pid1 > 0){
pid_t pid2 = fork();
if(pid2 == -1){
cout << "create pid2 failed" << endl;
exit(EXIT_FAILURE);
}else if(pid2 == 0){
sleep(2);
int rmisgid2 = msgget(key,IPC_CREAT | 0644);
if(rmisgid2 == -1){
cout << "rmisgid2 failed" << endl;
exit(EXIT_FAILURE);
}
MSGBUF sbuf2;
//清空sbuf1里的东西
bzero(&sbuf2,sizeof(sbuf2));
ssize_t rtypes = msgrcv(rmisgid2,&sbuf2,SIZE,MTYPE2,0);
if(rtypes == -1){
cout << "rtypes false"<< endl;
exit(EXIT_FAILURE);
}
cout << "rmisgid2接受到的消息是:";
printf("%s\n",sbuf2.mtext);
}else{
int msgid = msgget(key,IPC_CREAT | 0644);
//创建结构体buf1
MSGBUF buf1;
buf1.mtype = MTYPE1;
strcpy(buf1.mtext,"hellow world");
int ret = msgsnd(msgid,&buf1,SIZE,0);
if(ret == -1){
cout << "msgsnd failed" << endl;
exit(EXIT_FAILURE);
}
//创建结构体buf2
MSGBUF buf2;
buf2.mtype = MTYPE2;
strcpy(buf2.mtext,"hellow c++");
int ret1 = msgsnd(msgid,&buf2,SIZE,0);
if(ret1 == -1){
cout << "msgsnd1 failed" << endl;
exit(EXIT_FAILURE);
}
int figure = 0;
waitpid(-1,NULL,0);
waitpid(-1,NULL,0);
}
}
return 0;
}
示例图片: