基于流式套接字Socket的C/S通信设计(三)

共享内存

一、设计目的       

        提高进程间通信的效率。共享内存允许两个及以上进程访问同一块内存。访问共享内存和访问进程独有的内存区域一样快,并不需要通过系统调用或其它需要切入内核的过程完成;避免了对数据的各种不必要的复制。

        系统内核没有对访问共享内存的同步机制。我们通常使用信号量进行同步,避免在数据写入过程中被读取、两个进程同时写入等情况出现。

——管道 消息队列 共享内存的优缺点

https://blog.csdn.net/Helloo_jerry/article/details/77508180

 二、详细设计

共享内存头部设计

typedef struct shmhead_st
{
	int shmid;					// 共享内存ID

	unsigned int blocksize;		// 块大小
	unsigned int blocks;		// 总块数
	unsigned int rd_index;		// 读索引
	unsigned int wr_index;		// 写索引

	//必须放在共享内存内部
	sem_t sem_mutex;			// 互斥信号量
	sem_t sem_full;				// 判满信号量
	sem_t sem_empty;			// 判空信号量

}shmhead_t;

共享内存类的设计

lass ShmFIFO
{
public:
	ShmFIFO(int key, int blksize, int blocks);
	ShmFIFO();
	virtual ~ShmFIFO();
	//创建和销毁
	bool ShmInit(int key, int blksize, int blocks);
	void destroy(void);
	//静态删除共享内存方法
	static void ShmDestroy(int key); 

	//打开和关闭
	bool ShmOpen(int key, int blksize, int blocks);
	void ShmClose(void);

	//读取和存储
	void ShmWrite(const void* buf);
	void ShmRead(void* buf);
protected:
	//进程控制信息块
	bool m_open;
	//共享内存头部指针
	void* m_shmhead;
	//有效负载的起始地址
	char* m_payload;			
};

共享内存类的实现

ShmFIFO::ShmFIFO(int key, int blksize, int blocks)
{
	this->ShmOpen(key, blksize, blocks);
}

ShmFIFO::ShmFIFO()
{
	m_shmhead = NULL;
	m_payload = NULL;
	m_open = false;
}

ShmFIFO::~ShmFIFO()
{
	this->ShmClose();
}

/*返回头地址*/
bool ShmFIFO::ShmInit(int key, int blksize, int blocks)
{
	int shmid = 0;

	//1. 查看是否已经存在共享内存,如果有则删除旧的
	shmid = shmget((key_t)key, 0, 0);
	if (shmid != -1)
	{
		shmctl(shmid, IPC_RMID, NULL); 
	}

	//2. 创建共享内存
	shmid = shmget((key_t)key, sizeof(shmhead_t) + blksize * blocks, 0666 | IPC_CREAT | IPC_EXCL);
	if (shmid == -1)
	{
		perror("shmget");
		exit(-1);
	}
	printf("Create shmid=%d size=%ld \n", shmid, sizeof(shmhead_t) + blksize * blocks);

	//3.连接共享内存
	m_shmhead = shmat(shmid, (void*)0, 0);			
	if (m_shmhead == (void*)-1)
	{
		perror("shmat");
		exit(-1);
	}
	memset(m_shmhead, 0, sizeof(shmhead_t) + blksize * blocks);	

	//4. 初始化共享内存信息
	shmhead_t* pHead = (shmhead_t*)(m_shmhead);
	pHead->shmid = shmid;					//共享内存shmid
	pHead->blocksize = blksize;				//共享信息写入
	pHead->blocks = blocks;					//块大小
	pHead->rd_index = 0;					//初始位置都是第一块
	pHead->wr_index = 0;					
	sem_init(&pHead->sem_mutex, 1, 1);		// 第一个1表示可以跨进程共享,第二个1表示初始值
	sem_init(&pHead->sem_empty, 1, 0);		// 第一个1表示可以跨进程共享,第二个0表示初始值
	sem_init(&pHead->sem_full, 1, blocks);	// 第一个1表示可以跨进程共享,第二个blocks表示初始值

	//5. 填充控制共享内存的信息
	m_payload = (char*)(pHead + 1);	//实际负载起始位置
	m_open = true;

	return true;
}

void ShmFIFO::destroy()
{
	shmhead_t* pHead = (shmhead_t*)m_shmhead;
	int shmid = pHead->shmid;

	//删除信号量
	sem_destroy(&pHead->sem_full);
	sem_destroy(&pHead->sem_empty);
	sem_destroy(&pHead->sem_mutex);
	//共享内存脱离
	shmdt(m_shmhead); 

	//销毁共享内存
	if (shmctl(shmid, IPC_RMID, 0) == -1)
	{
		printf("Delete shmid=%d \n", shmid);
		perror("shmctl");
		exit(-1);
	}

	m_shmhead = NULL;
	m_payload = NULL;
	m_open = false;
}

void ShmFIFO::ShmDestroy(int key)
{
	int shmid = 0;

	//1. 查看是否已经存在共享内存,如果有则删除旧的
	shmid = shmget((key_t)key, 0, 0);
	if (shmid != -1)
	{
		printf("Delete shmid=%d \n", shmid);
		shmctl(shmid, IPC_RMID, NULL); 
	}
}

/*返回头地址*/
bool ShmFIFO::ShmOpen(int key, int blksize, int blocks)
{
	int shmid;

	this->ShmClose();

	//1. 查看是否已经存在共享内存,如果有则删除旧的
	shmid = shmget((key_t)key, 0, 0);
	if (shmid == -1)
	{
		return this->ShmInit(key, blksize, blocks);
	}

	//2.连接共享内存
	m_shmhead = shmat(shmid, (void*)0, 0);	
	if (m_shmhead == (void*)-1)
	{
		perror("shmat");
	}

	//3. 填充控制共享内存的信息
	m_payload = (char*)((shmhead_t*)m_shmhead + 1);	//实际负载起始位置
	m_open = true;

	return true;
}

void ShmFIFO::ShmClose(void)
{
	if (m_open)
	{
		//共享内存脱离
		shmdt(m_shmhead); 
		m_shmhead = NULL;
		m_payload = NULL;
		m_open = false;
	}
}

void ShmFIFO::ShmWrite(const void* buf)
{
	shmhead_t* pHead = (shmhead_t*)m_shmhead;

	sem_wait(&pHead->sem_full);									//是否有资源写?	可用写资源-1
	sem_wait(&pHead->sem_mutex);								//是否有人正在写?
	memcpy(m_payload + (pHead->wr_index) * (pHead->blocksize), buf, pHead->blocksize);
	pHead->wr_index = (pHead->wr_index + 1) % (pHead->blocks);	//写位置偏移		
	sem_post(&pHead->sem_mutex);								//解除互斥	
	sem_post(&pHead->sem_empty);								//可用读资源+1
}

void ShmFIFO::ShmRead(void* buf)
{
	shmhead_t* pHead = (shmhead_t*)m_shmhead;

	sem_wait(&pHead->sem_empty);								//检测写资源是否可用		
	sem_wait(&pHead->sem_mutex);
	memcpy(buf, m_payload + (pHead->rd_index) * (pHead->blocksize), pHead->blocksize);
	pHead->rd_index = (pHead->rd_index + 1) % (pHead->blocks);	//读位置偏移
	sem_post(&pHead->sem_mutex);								//解除互斥
	sem_post(&pHead->sem_full);									//增加可写资源	
}

 写端

typedef struct user        
{
	char UserName[32];
	char PassWord[32];
}USER_T;
int main(void)
{
	ShmFIFO shm(1234, sizeof(USER_T), 3);//写并发送

	USER_T user1 = { "Jack", "123456" };
	USER_T user2 = { "Rose", "123456" };
	USER_T user3 = { "Mick", "123456" };
	int n = 6;

	while (n)
	{
		shm.ShmWrite(&user1);
		printf("ShmWrite success \n");
		sleep(1);
		shm.ShmWrite(&user2);
		printf("ShmWrite success \n");
		sleep(1);
		shm.ShmWrite(&user3);
		printf("ShmWrite success \n");
		sleep(1);	
	}
	return 0;
}

读端

typedef struct user         
{
	char UserName[32];
	char PassWord[32];
}USER_T;

using namespace std;

int main(void)
{
	USER_T user;
	ShmFIFO shm(1234, sizeof(USER_T), 3);

	while (1)
	{
		memset(&user, 0, sizeof(USER_T));
		shm.ShmRead(&user);
		printf("ShmRead success.\n");
		printf("UserName = %s, PassWord = %s\n", user.UserName, user.PassWord);
	}

	return 0;
}

 测试结果

      

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LeoMove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值