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;
}
 
示例图片:
 
![re题(36)BUUCTF-[WUSTCTF2020]Cr0ssfun](https://i-blog.csdnimg.cn/direct/de2da2c8346a4ebeb43aa43315e688fb.png)


















