Linux进程间通信之共享内存

Linux进程间通信之共享内存

linux_shm.h文件

#ifndef LINUX_SHM__H_H
#define LINUX_SHM__H_H

#include <sys/types.h>
#include <unistd.h>

int create_shm(char *name, unsigned int size);
char* map_shm(int shmid);
void unmap_shm(char *shmaddr);
void close_shm(int shmid);


#endif

linux_shm.cpp文件

#include "linux_shm.h"
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>

#define PROJ_ID 	0x03


int create_shm(char *name, unsigned int size)
{
	int shmid;
	key_t shm_key;
	
	if ((shm_key = ftok(name, PROJ_ID)) == (key_t) -1) {
		perror(name);
		return -1;
	}
	
	shmid = shmget(shm_key, size, 0666|IPC_CREAT);
	if(shmid < 0 ) {
		perror(name);
		if (errno != EEXIST){
			return -1;
		}else {
			//shm already exists
			if((shmid = shmget(shm_key, size, SHM_R | SHM_W)) < 0) {
				perror(name);
				return -1;
			}
		}
	}
	
	return shmid;

}


char* map_shm(int shmid)
{
	char* pt;
	pt = (char *)shmat((int)shmid, 0, SHM_RND);
	if(pt == NULL) {
		perror("map error");
	}
	
	return pt;
}

void unmap_shm(char *shmaddr)
{
	shmdt(shmaddr);
	return ;
}


void close_shm(int shmid)
{
	struct shmid_ds buf;
    shmctl((int)shmid, IPC_RMID, &buf);
	return ;
}

mgr_shm.h文件

#ifndef MGR_SHM__H_H
#define MGR_SHM__H_H

#include "linux_shm.h"

#define SHM_KEY 		"shm.key"


#define REG_READ		0x01  		//读操作命令字
#define REG_WRITE		0x02		//写操作命令字

#define DATA_INVALID	0x00		//数据无效
#define DATA_VALID		0x01		//数据有效

//读寄存器的操作请求的消息结构体
typedef struct {
	unsigned char 	valid;			//数据是否可读标识,0:不可读 1:可读
	unsigned char 	csid;			//芯片片选id
	unsigned char  	cmd;			//读写操作命令字
	unsigned short 	regaddr;		//寄存器地址
} msg_rd_req;

//读寄存器的操作应答消息结构体
typedef struct {
	unsigned char 	valid;			//数据是否可读标识,0:不可读 1:可读
	unsigned char 	csid;			//芯片片选id
	unsigned short 	regaddr;		//寄存器地址
	unsigned char 	value;			//寄存器的值
} msg_rd_resp;

//写寄存器的操作请求的消息结构体
typedef struct {
	unsigned char 	valid;			//数据是否可读标识,0:不可读 1:可读
	unsigned char 	csid;			//芯片片选id
	unsigned char  	cmd;			//读写操作命令字
	unsigned short 	regaddr;		//寄存器地址
	unsigned char 	value;			//寄存器的值
} msg_wr_req;

//写寄存器的操作应答消息结构体
typedef struct {
	unsigned char 	valid;			//数据是否可读标识,0:不可读 1:可读
	unsigned char 	csid;			//芯片片选id
	unsigned short 	regaddr;		//寄存器地址
	unsigned char 	status;			//写入寄存器地址中的值成功与否,0:成功 -1:失败
} msg_wr_resp;

typedef struct {
	msg_wr_req		wr_req;
	msg_wr_resp		wr_resp;
	msg_rd_req		rd_req;
	msg_rd_resp		rd_resp;
} msg;

int attach_shm(const char* keypath);
void detach_shm(int shmid);

msg* get_msg();
void init_msg(msg* ptr);
void print_msg(const msg* ptr);


#endif

mgr_shm.cpp文件

#include "mgr_shm.h"
#include "string.h"
#include <stdio.h>

static msg* pMsg = NULL;
static void set_msg(msg* ptr)
{
	pMsg = ptr;
}




int attach_shm(const char* keypath)
{
	int chshm;
	char    cFileName [256];
	sprintf(cFileName,"%s/%s",keypath,SHM_KEY);
	 
	chshm = create_shm((char *)cFileName,sizeof(msg));
	pMsg = (msg*)map_shm(chshm);
	if (pMsg == NULL )
	{		
		return -1;
	}
	return chshm ;
}


void detach_shm(int shmid)
{
	unmap_shm((char*)pMsg);
	close_shm(shmid);
}

msg* get_msg()
{
	return pMsg;
}


void init_msg(msg* ptr)
{
	if(ptr == NULL)
		return ;
	
	ptr->rd_req.valid = 0;
	ptr->rd_req.csid = 0;
	ptr->rd_req.cmd = 0;
	ptr->rd_req.regaddr = 0;
	
	ptr->wr_req.valid = 0;
	ptr->wr_req.csid = 0;
	ptr->wr_req.cmd = 0;
	ptr->wr_req.regaddr = 0;
	ptr->wr_req.value = 0;	
	
	
	ptr->rd_resp.valid = 0;
	ptr->rd_resp.csid = 0;
	ptr->rd_resp.regaddr = 0;
	ptr->rd_resp.value = 0;
	
	ptr->wr_resp.valid = 0;
	ptr->wr_resp.csid = 0;
	ptr->wr_resp.regaddr = 0;
	ptr->wr_resp.status = 0;		
}

void print_msg(const msg* ptr)
{
	if(ptr == NULL)
		return ;
	
	printf("ptr->rd_req.valid=%d\n",ptr->rd_req.valid);
	printf("ptr->rd_req.csid=%d\n",ptr->rd_req.csid);
	printf("ptr->rd_req.cmd=%d\n",ptr->rd_req.cmd);
	printf("ptr->rd_req.regaddr=%d\n",ptr->rd_req.regaddr);
	

	printf("ptr->rd_resp.valid=%d\n",ptr->rd_resp.valid);
	printf("ptr->rd_resp.csid=%d\n",ptr->rd_resp.csid);
	printf("ptr->rd_resp.regaddr=%d\n",ptr->rd_resp.regaddr);
	printf("ptr->rd_resp.value=%d\n",ptr->rd_resp.value);


	printf("ptr->wr_req.valid=%d\n",ptr->wr_req.valid);
	printf("ptr->wr_req.csid=%d\n",ptr->wr_req.csid);
	printf("ptr->wr_req.cmd=%d\n",ptr->wr_req.cmd);
	printf("ptr->wr_req.regaddr=%d\n",ptr->wr_req.regaddr);
	printf("ptr->wr_req.value=%d\n",ptr->wr_req.value);	
	
	
	printf("ptr->wr_resp.valid=%d\n",ptr->wr_resp.valid);
	printf("ptr->wr_resp.csid=%d\n",ptr->wr_resp.csid);
	printf("ptr->wr_resp.regaddr=%d\n",ptr->wr_resp.regaddr);
	printf("ptr->wr_resp.status=%d\n",ptr->wr_resp.status);
}


server_shm.cpp文件

#include <stdio.h>
#include <string>
#include "mgr_shm.h"
#include "linux_shm.h"


int main(int argc,char** argv)
{
	int shmid = attach_shm("/home/banting/test/shm_demo");
	msg* ptr = get_msg();
	
	while(1)
	{
		
		if(ptr->wr_req.valid == DATA_VALID)
		{
			ptr->wr_resp.valid = DATA_INVALID;
			ptr->wr_resp.csid = ptr->wr_req.csid;
			ptr->wr_resp.regaddr = ptr->wr_req.regaddr;
			ptr->wr_resp.status = 0x00;
			ptr->wr_resp.valid = DATA_VALID;
		}
		
		
		if(ptr->rd_req.valid == DATA_VALID)
		{
			ptr->rd_resp.valid = DATA_INVALID;
			ptr->rd_resp.csid = ptr->rd_req.csid;
			ptr->rd_resp.regaddr = ptr->rd_req.regaddr;
			ptr->rd_resp.value = 0x40;
			ptr->rd_resp.valid = DATA_VALID;
		}
		
		sleep(2);
	}
	
	detach_shm(shmid);
	ptr = NULL;

	return 0;
}

client_shm.cpp文件

#include <stdio.h>
#include <string.h>
#include <string>
#include "mgr_shm.h"
#include "linux_shm.h"

static void write_reg(int csid , unsigned short regaddr, unsigned char value)
{
	int shmid = attach_shm("/home/banting/test/shm_demo");
	msg* ptr = get_msg();
	init_msg(ptr);
	
	
	ptr->wr_req.csid = csid;
	ptr->wr_req.cmd = REG_WRITE;
	ptr->wr_req.regaddr = regaddr;
	ptr->wr_req.value = value;
	ptr->wr_req.valid = DATA_VALID;

	while(ptr->wr_resp.valid != DATA_VALID)
	{
		sleep(1);
	}
	
	print_msg(ptr);
	sleep(1);
	ptr->wr_req.valid = DATA_INVALID;
	//客户端不需要去释放内存,由服务端去释放
	//否则客户多次重连,会出多个共享内存情况,两个进程无法通信
	//detach_shm(shmid);
	
	return ;
}


static void read_reg(int csid , unsigned short regaddr)
{
	int shmid = attach_shm("/home/banting/test/shm_demo");
	msg* ptr = get_msg();
	init_msg(ptr);
	
	
	ptr->rd_req.csid = csid;
	ptr->rd_req.cmd = REG_READ;
	ptr->rd_req.regaddr = regaddr;
	ptr->rd_req.valid = DATA_VALID;

	while(ptr->rd_resp.valid != DATA_VALID)
	{
		sleep(1);
	}
	
	print_msg(ptr);
	sleep(1);
	ptr->rd_req.valid = DATA_INVALID;
	//客户端不需要去释放内存,由服务端去释放
	//否则客户多次重连,会出多个共享内存情况,两个进程无法通信
	//detach_shm(shmid);
	
	return;
}

static void trim(std::string& src_string)
{
	src_string.erase(0,src_string.find_first_not_of(" \r\n\t\v\f"));
	src_string.erase(src_string.find_last_not_of(" \r\n\t\v\f") +1);
}

int main(int argc, char** argv)
{
	if((argc == 5) && (strcmp(argv[1],"write_reg") == 0))
	{
		std::string csid_str(argv[2]);
		trim(csid_str);
		unsigned char csid = std::stoi(csid_str);
		
		std::string regaddr_str(argv[3]);
		trim(regaddr_str);
		regaddr_str = regaddr_str.substr(2);
		unsigned short regaddr = std::stoi(regaddr_str,nullptr,16);
		
		std::string regvalue_str(argv[4]);
		trim(regvalue_str);
		unsigned char regvalue = std::stoi(regvalue_str);
		
		write_reg(csid, regaddr,regvalue);
	} 
	else if((argc == 4) && (strcmp(argv[1],"read_reg") == 0))	
	{
		std::string csid_str(argv[2]);
		trim(csid_str);
		unsigned char csid = std::stoi(csid_str);
		
		std::string regaddr_str(argv[3]);
		trim(regaddr_str);
		regaddr_str = regaddr_str.substr(2);
		unsigned short regaddr = std::stoi(regaddr_str,nullptr,16);

		read_reg(csid, regaddr);
	}
	else 
	{
		return -1;
	}
	
	return 0;
}	

编译

[banting@localhost shm_demo]g++ -g -std=c++11 linux_shm.cpp mgr_shm.cpp client_shm.cpp -o client_shm
[banting@localhost shm_demo]g++ -g -std=c++11 linux_shm.cpp mgr_shm.cpp server_shm.cpp -o server_shm
[banting@localhost shm_demo] ls -tlr
-rw-rw-r-- banting banting 0 	  Jul 29 16:19 shm.key
-rw-rw-r-- banting banting 944 	  Jul 29 16:19 linux_shm.cpp
-rw-rw-r-- banting banting 2096   Jul 29 16:19 client_shm.cpp
-rw-rw-r-- banting banting 242    Jul 29 16:19 mgr_shm.cpp
-rw-rw-r-- banting banting 802    Jul 29 16:19 linux_shm.h
-rw-rw-r-- banting banting 1775   Jul 29 16:19 server_shm.cpp
-rw-rw-r-- banting banting 2518   Jul 29 16:19 mgr_shm.h
-rw-rw-r-- banting banting 19304  Jul 29 16:19 client_shm
-rw-rw-r-- banting banting 13648  Jul 29 16:19 server_shm

运行

[banting@localhost shm_demo] ./server_shm
[banting@localhost shm_demo] ./client_shm write_reg 1 0x301 9
ptr->rd_req.valid = 0;
ptr->rd_req.csid = 0;
ptr->rd_req.cmd = 0;
ptr->rd_req.regaddr = 0;
ptr->rd_resp.valid = 0;
ptr->rd_resp.csid = 0;
ptr->rd_resp.regaddr = 0;
ptr->rd_resp.value = 0;
ptr->wr_req.valid = 1;
ptr->wr_req.csid = 1;
ptr->wr_req.cmd = 2;
ptr->wr_req.regaddr = 769;
ptr->wr_req.value = 9;	
ptr->wr_resp.valid = 1;
ptr->wr_resp.csid = 1;
ptr->wr_resp.regaddr = 769;
ptr->wr_resp.status = 0;
[banting@localhost shm_demo]	

查看哪些进程attach共享内存

#方式一:通过 lsof |grep shmid  这种方式不适合shmid为0的情况查看
[banting@localhost shm_demo]# ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00123456 0          root       664        5497632    0                       
0x65000006 32769      root    	 664        4096       0                       
0x03003f5a 229379     banting    666        26         1                       

[banting@localhost shm_demo]# lsof |grep 229379
server_sh 12339      banting	DEL       REG                0,4              229379 /SYSV03003f5a


#方式二:通过lsof | grep key   这种方式更通用
[banting@localhost shm_demo]# ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00123456 0          root       664        5497632    0                       
0x65000006 32769      root       664        4096       0                       
0x03003f5a 229379     banting    666        26         1                       

[banting@localhost shm_demo]# lsof | grep 03003f5a
server_sh 12339      banting	DEL       REG                0,4              229379 /SYSV03003f5a

[banting@localhost shm_demo]# ps -ef |grep 12339
root     12339 12320  0 08:20 ?        00:00:02 ./server_shm
root     16142  7475  0 08:51 pts/5    00:00:00 grep --color=auto 12339
root@gb:/home/gb/USB-Device-Mgr/USB-Device-Mgr/bin#

参考文献:

【Linux 系统】进程间通信(共享内存、消息队列、信号量)
在linux下查看有哪些操作系统进程正在使用某一个共享内存段

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值