进程间通信IPC(共享内存) 03.23

IPC六种技术:

–(1)管道(pipe)和命名管道(FIFO ---- 最大传输容量65535byte;文件容易被误删;

–(2)信号(signal)

–(3)消息队列 -----消息队列也有管道一样的不足,就是每个数据块的最大长度是有上限的

–(4)共享内存

–(5)信号量

–(6)套接字(socket)网络

~# ipcs ----查询共享内存

~#ipcrm -h

~#ipcrm -m (shmid)

~#ipcrm -a 删除所有用户所开的共享内存

共享内存,内存不属于任何进程和程序,只属于系统

shmget()

功能:创建共享内存

返回:如果共享内存创建成功,*shmget将返回一个非负整数,即该段共享内存的标识码;如果失败,则返回-1

int shmget(key_t key,size_t size, int shmflg);
//key: 这个共享内存段的名字,如果key不存在则创建,存在则不做任何操作
//size: 需要共享的内存量
//shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的(九个模式mode----0777-----可读可写可执行)
shmat()

功能:共享内存段刚被创建的时候,任何进程还都不能访问它,为了建立对这个共享内存段的访问渠道,必须使用shmat把该共享内存连接到某个进程的地址空间。

返回:成功,返回一个指针,指针指向共享内存的第一个字节;失败,则返回 -1

void* shmat(int shm_id,const void *shm_addr,int shmflg);
//shm_id: shmget返回的共享内存标识
//shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址
//shmflg:是一组按位or(或)在一起的标志。它的两个可能取值是SHM_RND和SHM_RDONLY

•shm_addr==0:核心自动选择一个地址

•shm_addr!=0&&shmflg!=SHM_RND : 以shmaddr为连接地址。

•shm_addr!=0&&shmflg设==SHM_RND : 连接的地址会自动向下调整为SHMLBA的整数倍。公式: shm_addr- (shm_addr% SHMLBA)

•shmflg==SHM_RDONLY : 表示连接操作用来只读共享内存

•在fork() 后,子进程继承已连接的共享内存

•在exec()或结束进程后,已连接的共享内存会自动脱离(detach)

shmdt()

功能:把共享内存与当前进程脱离开

返回:操作成功,返回0,失败则返回 -1

注意:脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已

int shmdt(const void *shm_addr);
//shm_addr: 由shmat返回的地址指针

shmctl函数 — 少用,数据直接覆盖就可以了

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

WMain.cpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
typedef struct stu
{
	char stuid[10];
	char name[20];
}STU;


int main()//写段
{
	int shmid = 0;
	void *shmaddr;

	STU stu1 = { "OMO210815","wubingtu" };

	shmid = shmget((key_t)1001, 2048, IPC_CREAT|0777);//0777---对象不是文件,不需要使用umask()
	if (shmid == -1)
	{
		perror("shmget error:");
	}
	else 
	{
		//连接共享内存,获取共享内存的首地址
		shmaddr=shmat(shmid,NULL,0 );//第二个参数---共享内存的地址
		//写入数据--内存拷贝
		//void *memcpy(void *dest, const void *src, size_t n);
		memcpy(shmaddr,&stu1,sizeof(STU));
	}
	return 0;
}
RMain.cpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
typedef struct stu
{
	char stuid[10];
	char name[20];
}STU;

int main()
{
	int shmid = 0;
	void* shmaddr;
	STU resstu={0};

	shmid = shmget((key_t)1001, 2048, IPC_CREAT | 0777);//0777不是文件,不用使用umask()
	if (shmid == -1)
	{
		perror("shmget error:");
	}
	else
	{
		//连接共享内存,获取共享内存的首地址
		shmaddr = shmat(shmid, NULL, 0);//第二个参数---共享内存的地址
		//写入数据--内存拷贝
		//void *memcpy(void *dest, const void *src, size_t n);
		memcpy(&resstu, shmaddr, sizeof(STU));
		cout << resstu.stuid <<"  " << resstu.name << endl;
		
		//memset(shmid,0,sizeof(shmid));  bzero
		shmdt(shmaddr);
	}
}

作业一:

1.模仿课堂案例,使用共享内存完成要求如下:

1)定义聊天结构体,结构如下

struct chat

{

char uid[10];

char msg[50];

}

2)A程序和B程序两个工程,两个工程存在同样的结构体,用户名可以定死

3)程序运行A程序可以向B程序发送消息,msg消息通过控制台输入

4)B程序也可以向A程序发送消息,步骤同上

5)A和B都可以看到对方发送的消息如 “[用户名]对我说:xxx”的信息

自己的方案,有逻辑上的BUG

A point

#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
#include <unistd.h>
using namespace std;

typedef struct chat
{
	char uid[20];
	char msg[100];
}chat;

int main()
{
	int shmid_a2b = 0;
	int shmid_b2a = 0;
	void* shmaddr_a2b;
	void* shmaddr_b2a;
	chat a={ "machineA" };
	chat b;
	shmid_a2b = shmget((key_t)1001, 2048, IPC_CREAT | 0777);
	shmid_b2a = shmget((key_t)1002, 2048, IPC_CREAT | 0777);
	if (shmid_a2b == -1|| shmid_b2a == -1)
	{
		perror("shmget error:");
	}
	else
	{
		while (1)
		{
			bzero(a.msg, sizeof(a.msg));
			bzero(b.msg, sizeof(b.msg));

			cout << "A2B" << endl;
			fgets(a.msg, sizeof(a.msg), stdin);
			shmaddr_a2b = shmat(shmid_a2b, NULL, 0);
			memcpy(shmaddr_a2b, &a, sizeof(chat));

			sleep(5);

			shmaddr_b2a = shmat(shmid_b2a, NULL, 0);
			memcpy(&b, shmaddr_b2a, sizeof(chat));
			if (strlen(b.msg) != 0)
			{
				cout << b.uid << " say:  " << b.msg ;
				memset(b.msg, 0, sizeof(b.msg));
			}
		}
	}
	shmdt(shmaddr_a2b);
	shmdt(shmaddr_b2a);
	return 0;
}

B point

#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
#include <unistd.h>
using namespace std;

typedef struct chat
{
	char uid[20];
	char msg[100];
}chat;

int main()
{
	int shmid_a2b = 0;
	int shmid_b2a = 0;
	void* shmaddr_a2b;
	void* shmaddr_b2a;
	chat b = { "machineB" };
	chat a;
	shmid_a2b = shmget((key_t)1001, 2048, IPC_CREAT | 0777);
	shmid_b2a = shmget((key_t)1002, 2048, IPC_CREAT | 0777);
	if (shmid_a2b == -1 || shmid_b2a == -1)
	{
		perror("shmget error:");
	}
	else
	{
		while (1)
		{
			bzero(b.msg, sizeof(b.msg));
			bzero(a.msg, sizeof(a.msg));

			cout << "B2A" << endl;
			shmaddr_a2b = shmat(shmid_a2b, NULL, 0);
			memcpy(&a, shmaddr_a2b, sizeof(chat));
			if (strlen(a.msg) != 0)
			{
				cout << a.uid << " say:  " << a.msg ;
				memset(a.msg, 0, sizeof(a.msg));
			}

			sleep(5);

			fgets(b.msg, sizeof(b.msg), stdin);
			shmaddr_b2a = shmat(shmid_b2a, NULL, 0);
			memcpy(shmaddr_b2a, &b, sizeof(chat));
		}
	}
	shmdt(shmaddr_a2b);
	shmdt(shmaddr_b2a);
	return 0;
}

进阶版(消息队列+共享内存 方案)

A point


B point


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐