1. 创建key值
comm.hpp 公共路径中构建一个函数 Getkey 用于返回key值
构建一个函数 tohex,用于将数转换为十六进制
通过server.cc与client.cc中分别调用Getkey 与tohex函数
两者的返回值key 是相同的,并且返回的都是十六进制数
2. 创建共享内存 获取共享内存
创建共享内存,调用shmget函数,通过两个选项 若共享内存不存在则创建,若存在则报错
而获取共享内存,调用shmget函数,则返回已有的共享内存
此时运行可执行程序,发现server与client的shmid(共享内存标识符)相同
3. 将自己和共享内存关联起来
输入 man shmat
指令
at代表 关联
将共享内存和目标值关联起来
返回值为 共享内存的虚拟地址的起始地址
我们不知道应该把共享内存放在虚拟空间的什么地址处,所以shmaddr设为NULL让系统自主去选择
shmflg 可以设置为 SHM_RDONLY 表示当前共享内存是只读的 一般设为0,默认为读写的
4. 将自己和共享内存取消关联
输入 man shmdt
指令
shmdt代表 虚拟地址
成功返回0,失败返回-1
5. 删除共享内存
创建共享内存的进程已经早就退出了,但是共享内存还存在
确认共享内存存在: ipcs
ipc作为进程间通信的简写
ipc表示资源 s表示有多个资源
显出来的为ipc通信系统所支持的三种ipc通信策略
Message Queues 消息队列
Shared Memory Segments 共享内存段
Semaphore Arrays 信号量
ipcs - m 查看共享内存段
perms 代表权限
bytes 代表字节数
nattch 代表 有几个进程和当前进程是关联的
用指令删除
key是在操作系统中使用的,类似于文件的inode编号
shmid 类似于文件的fd
所以删除操作,是在用户层,应该用shmid
ipcrm -m shmid值
就可以删除共享内存
此时就没有 shmid为0的共享内存 存在了
调用系统调用
输入 man shmctl
指令
shmid 代表 共享内存描述符 即想对那个共享内存操作
cmd 代表 选项 即想做什么操作
IPC_STAT 获取当前共享内存的属性
IPC_SET 设置共享内存属性
IPC_RMID 标记这个段被释放
buf 代表 共享内存的属性
在comm.hpp下 设置删除共享内存的函数,在server.cc中调用函数 即可删除共享内存
完整代码
makefile
.PHONY:all all:server client server:server.cc g++ -o $@ $^ client:client.cc g++ -o $@ $^ .PHONY:clean clean: rm -f server client
如何使两个可执行程序运行,在上一篇文章提到过,点击查看:命名管道
comm.hpp
#ifndef _COMM_HPP_ #define _COMM_HPP_ #include<iostream> #include<cerrno> #include<cstdio> #include<cstring> #include<stdlib.h> #include<sys/ipc.h> #include<sys/shm.h> #include<sys/types.h> #include<assert.h> using namespace std; #define PATHNAME "."//.表示当前路径 路径字符串 #define PROJID 0x6666 //项目id const int gsize=4096; key_t getkey()//用于返回key值 { key_t k=ftok(PATHNAME,PROJID); if(k==-1)//失败 { cout<<errno<< " :" <<strerror(errno)<<endl; exit(1); } return k;//返回key值 } string tohex(int x)//转换为十六进制 { char buffer[64]; //将x以十六进制的形式传给buffer snprintf(buffer,sizeof(buffer),"0x%x",x); return buffer; } static int createshmhelper(key_t k,int size,int flag)//static修饰只在本文件有效 { int shmid=shmget(k,size,flag); if(shmid==-1)//创建失败 { cout<<errno<< " :" <<strerror(errno)<<endl; exit(2); } return shmid;//返回共享内存标识符 } int createshm(key_t k,int size)//创建共享内存 { //带有两个选项 若不存在则创建,若存在则报错 return createshmhelper(k,size,IPC_CREAT |IPC_EXCL); } int getshm(key_t k,int size) { //若有共享内存,则返回已有的共享内存 return createshmhelper(k,size,IPC_CREAT ); } char* attachshm(int shmid)//关联 { char*start=(char*)shmat(shmid,NULL,0);//对应类型void* 所以需要强转 return start; } void detachshm(char*start)//取消关联 { int n=shmdt(start); assert(n!=-1); (void)n; } void delshm(int shmid) { int n=shmctl(shmid,IPC_RMID,NULL); assert(n!=-1);//为-1就删除失败 (void)n; } #endif
server.cc
#include"comm.hpp" #include<unistd.h> int main() { //1. 创建key值 key_t k=getkey();//获取key值 cout<<"server:"<<tohex(k)<<endl; //2.创建共享内存 int shmid=createshm(k,gsize);//返回的是共享内存标识符 cout<<"server shmid:"<<shmid<<endl;//将共享内存标识符转换为十六进制 sleep(5); // 3.将自己和共享内存关联起来 char*start=attachshm(shmid); //通信 //4. 将自己和共享内存取消关联 detachshm(start); //5.删除共享内存 delshm(shmid); return 0; }
client.cc
#include"comm.hpp" int main() { key_t k=getkey();//获取key值 cout<<"client key:"<<tohex(k)<<endl; int shmid=getshm(k,gsize);//获取共享内存 cout<<"client shmid:"<<shmid<<endl;//将共享内存标识符转换为十六进制 char*start=attachshm(shmid); detachshm(start); return 0; }