1. 什么是共享内存
1. 是一块独立于两个通信进程的内存空间,通过对这块的读写操作实现进程间通信。
2. 优缺点
1. 操作方便;
2. 无大小限制;
3. 无阻塞函数,难以实现即时接收;
2. 共享内存的操作
void* shmadr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT|0777);
shmadr = shmat(shmid, NULL, 0);//连接
memcpy(shmadr, &stu, sizeof(STU));//写入/读出
shmdt(shmadr);//断开
1. Shmget()根据键值、大小、权限为创建新的共享内存 或 获取已有的共享内存;
2. Shmat()连接函数,通过文件描述符返回共享内存初地址;
- 案例:见最后
3. 消息队列SHM与共享内存MSG配合实现即时通信
- 结合消息列表(或管道)的阻塞的特点,实现即时通讯;
- 最好在读共享内存后清空内存块(根据实际业务);
-
创建一个消息队列可以两端同时读写,不区分哪个端口;
案例
【案例1:共享内存】
写端:
#include<iostream>
using namespace std;
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
typedef struct student {
char stuid[20];
char stuname[20];
}STU;
int main()
{
STU stu = { "00001","壹号" };
void* shmadr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT|0777);
if (shmid == -1)
{
perror("shmid error");
}
else {
shmadr = shmat(shmid, NULL, 0);//连接
memcpy(shmadr, &stu,sizeof(STU));//写入
cout << "写入" << stu.stuid << stu.stuname << endl;
shmdt(shmadr);//断开
}
return 0;
}
读端:
int main()
{
STU stu = { 0 };
void* shmadr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT | 0777);
if (shmid == -1)
{
perror("shmid error");
}
else {
shmadr = shmat(shmid, NULL, 0);//连接
memcpy( &stu, shmadr,sizeof(STU));//读出
cout << "读出" << stu.stuid << stu.stuname << endl;
shmdt(shmadr);//断开
}
return 0;
}
实例2【SHM与MSG实现即时通信】
写端:
#include<iostream>
using namespace std;
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
//实现不同的功能:
//数据会丢失,单一共享内存(目前只能这样)
//双端堵塞等待发送
typedef struct student {
int num;
char name[20];
char number[20];
}STU;
typedef struct Msgbuf
{ long mtype;
char mtext[50];
}MSGBUF;
int main()
{
int msgid = msgget((key_t)1003, IPC_CREAT | 0777);
if (msgid == -1) {
perror("msgget error");
}
else {
cout << "消息队列创建成功" << endl;
}
MSGBUF buf = {0};
buf.mtype = 1;
void* shmaddr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT | 0777);
if (shmid == -1) {
perror("shmget error");
}
else {
cout << "共享内存创建成功" << endl;
}
cout << "等待收端连接……(msgrcv阻塞)" << endl;
msgrcv(msgid, &buf, sizeof(buf), 1, 0);
cout << "双端连接成功!\n"<< endl;
shmaddr = shmat(shmid, NULL, 0); //获得共享内存地址
for (int i = 0; i < 3; i++)
{
int k = 0;
cin >> k;
sleep(1);
STU stu = { i,"000001","壹号" };
memcpy(shmaddr,&stu,sizeof(stu)); //写入
cout << "写入至共享内存: " << stu.num << stu.name << stu.number << endl;
msgsnd(msgid, &buf, sizeof(buf), 0);//发送消息队列
cout << "已通知(发送消息队列)" << endl;
}
return 0;
}
读端:
#include<iostream>
using namespace std;
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//实现不同的功能:
//数据会丢失,单一共享内存(目前只能这样)
//双端堵塞等待发送
typedef struct student {
int num;
char name[20];
char number[20];
}STU;
typedef struct Msgbuf
{
long mtype;
char mtext[50];
}MSGBUF;
int main()
{
int msgid = msgget((key_t)1003, IPC_CREAT | 0777);
if (msgid == -1) {
perror("msgget error");
}
else {
cout << "消息队列创建成功" << endl;
}
MSGBUF buf = { 0 };
buf.mtype = 1;
void* shmaddr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), 0);
if (shmid == -1) {
perror("shmget error");
}
else {
cout << "共享内存创建成功" << endl;
}
msgsnd(msgid, &buf, sizeof(buf), 0);//发送消息队列
cout << "请求发端连接" << endl;
shmaddr = shmat(shmid, NULL, 0); //获得共享内存地址
for (int i = 0; i < 3; i++)
{
STU stu = { 0 };
cout << "等待接收(msgrcv处于阻塞状态)" << endl;
ssize_t res = msgrcv(msgid, &buf, sizeof(buf), 1, 0);
cout << "已接收通知(接受消息队列)" << res <<endl;
memcpy(&stu, shmaddr, sizeof(stu)); //读出
cout << "读出成功: " << stu.num << stu.name << stu.number << endl;
}
return 0;
}