Linux——命名管道及日志-CSDN博客
文章目录
目录
文章目录
前言
一、system V消息队列是什么?
二、相关库接口
1.shmget接口
2、ftok接口
3、shmget、ftok接口封装
4、共享内存操作
编辑
5、shmdt接口
三.函数的调用
1、查看共享内存
2、shell
四、连个进程进行交互
总结
前言
在之前我们手搓管道时,我们知道进程和进程之间想要通信,我们得有一块公共的内存来进行数据的交互
一、system V消息队列是什么?
- 定义
- System V 消息队列是 System V IPC(Inter - Process Communication,进程间通信)机制中的一种。它提供了一种在不同进程之间传递消息的方式,这些进程可以在同一台计算机上运行。消息队列允许一个进程向消息队列发送消息,而另一个进程从这个消息队列中读取消息,从而实现进程间的异步通信。
二、相关库接口
1.shmget接口
shmget -分配一个系统V共享内存段
默认大小是4096字节也就是4kb 如果说我们想申请4097字节,但是实际上是4096*2,但是我们只能访问4097个字节
参数:
研究参数key的类型key_t;
1、key是一数字,这个数字是几,不重要,关键在于它必须在内核中具有唯一性,能够让不同的进程进行唯一性标识;
2、第一个进程可以通过key创建共享内存,第二个之后的进程,只要拿着同一个key就可以和第一个进程看到同一个共享内存!
3、对于一个已经创建好了的共享内存,key在哪?
key在共享内存的描述对象中。
4、第一次创建的时候,必须要有一个key了。
怎么有?
shmflg和我们前面讲的open一样,它的参数也是宏定义
IPC_CREAT(单独使用):如果申请的共享内存不存在就创建,如果存在就获取它shmid;
IPC_CREAT|IPC_EXCL:如果申请的共享内存不存在,就创建,存在就退出错误码,确保我们申请的共享内存是一个新的;
返回值:
2、ftok接口
获取key函数
参数
返回值key_t
这个接口是一套算法,pathname和proj_id进行数值计算
由用户约定它们的值。
3、shmget、ftok接口封装
写一段代码封装一下这两个库函数。
#include "log.hpp"
using namespace std;
const int size = 4096;
const string pathname = "/home/whb";
const int proj_id = 0x6666;
Log log;
key_t Getkey()
{key_t k = ftok(pathname.c_str(), proj_id);if (k < 0){log(Fatal, "ftok error: %s", strerror(errno));exit(1);}log(Info, "ftok success, key is : 0x%x", k);return k;
}int GetShareMemHelper(int flag)
{key_t k = Getkey();int shmid = shmget(k, size, flag);if (shmid < 0){log(Fatal, "create share memory error: %s", strerror(errno));exit(2);}log(Info, "create share memory success, shmid: %d", shmid);return shmid;
}int CreateShm()
{return GetShareMemHelper(IPC_CREAT | IPC_EXCL | 0666);
}int GetShm()
{return GetShareMemHelper(IPC_CREAT);
}
4、共享内存操作
参数:
我们知道不管什么东西在操作系统中出现都是先描述后组织的过程;而这个shmid就相当共享内存空间的pid,他就是shmget的返回参数;
//ipc code 在这里!!
// 一旦有人把数据写入到共享内存,其实我们立马能看到了!!
// 不需要经过系统调用,直接就能看到数据了!
这个函数和c语言的malloc函数相似
返回值:
5、shmdt接口
用来断开与共享空间的连接;
三.函数的调用
#include"comm.hpp"int main()
{//Init init;//创建共享空间sleep(3);log(Debug,"先休眠3秒");int shmid=CreateShm();log(Debug,"测试创建共享空间 shmid为: %d",shmid);//让进程a与共享空间连接char* shmaddr=(char*)shmat(shmid,nullptr,0);log(Debug,"进程连接空型空间");sleep(4);log(Debug,"先休眠4秒");//断开进程a与共享空间的连接int s=shmdt(shmaddr);log(Debug,"断开与共享空间的连接 %d",s);return 0;
}
1、查看共享内存
ipcs -m
共享内存的生命周期是随内核的,用户不主动关闭,共享内存就一直存在。
除非内核重启(用户释放)
2、shell
使用ipcs 添加参数-m可以查看系统中共享内存的详细信息
ipcs -m
使用 ipcrm 命令可以标记删除某块共享内存
# key == shmget的第一个参数
$ ipcrm -M shmkey
# id == shmget的返回值
$ ipcrm -m shmid
四、连个进程进行交互
我们发现当我们不输入时,进程b一直在共享空间中读取上一条数据,那么怎么改善的?
答案是结合管道
进程A
#include"comm.hpp"int main()
{Init init;//创建共享空间sleep(3);log(Debug,"进程A先休眠3秒");int shmid=CreateShm();log(Debug,"测试创建共享空间 shmid为: %d",shmid);//让进程a与共享空间连接char* shmaddr=(char*)shmat(shmid,nullptr,0);log(Debug,"进程A连接空型空间");int fd = open(FIFO_FILE, O_WRONLY); // 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!if (fd < 0){log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);exit(FIFO_OPEN_ERR);}// 一旦有了共享内存,挂接到自己的地址空间中,你直接把他当成你的内存空间来用即可!// 不需要调用系统调用// ipc codewhile (true){cout << "Please Enter@ ";fgets(shmaddr, 4096, stdin);write(fd, "c", 1);}sleep(4);log(Debug,"A先休眠4秒");//断开进程a与共享空间的连接int s=shmdt(shmaddr);log(Debug,"A断开与共享空间的连接 %d",s);return 0;
}
进程B
#include"comm.hpp"int main()
{//Init init;//创建共享空间sleep(3);log(Debug,"进程B先休眠3秒");int shmid=GetShm();log(Debug,"测试创建共享空间 shmid为: %d",shmid);//让进程a与共享空间连接char* shmaddr=(char*)shmat(shmid,nullptr,0);log(Debug,"进程B连接空型空间");int fd = open(FIFO_FILE, O_RDONLY); // 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!if (fd < 0){log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);exit(FIFO_OPEN_ERR);}while(true){char c;ssize_t s = read(fd, &c, 1);if(s == 0) break;else if(s < 0) break;cout << "client say@ " << shmaddr << endl; //直接访问共享内存sleep(1);}sleep(4);log(Debug,"进程B先休眠4秒");//断开进程a与共享空间的连接int s=shmdt(shmaddr);log(Debug,"进程B断开与共享空间的连接 %d",s);return 0;
}
总结
共享内存是在内存是唯一确定的,并且它们都是由操作系统先描述再组织的!