共享内存是一种高效的进程间通信(IPC)方式,允许多个进程访问同一块内存区域。通过共享内存,进程之间可以直接读写数据,而无需经过操作系统的中介,从而减少了上下文切换的开销。在服务端和客户端通信中,服务端通常会创建共享内存并将数据写入该区域,客户端可以直接读取该数据。由于共享内存不需要通过管道、套接字等其他通信方式,因此在高性能应用中非常有用。实现简单的服务端与客户端通信时,服务端负责创建并初始化共享内存,客户端则连接到该内存并读取或写入数据。这样,双方可以通过共享内存高效地交换信息。
💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力! 👍点赞、收藏与分享:觉得这篇文章对你有帮助吗?别忘了点赞、收藏并分享给更多的小伙伴哦!你们的支持是我不断进步的动力! 🚀分享给更多人:如果你觉得这篇文章对你有帮助,欢迎分享给更多对Linux OS感兴趣的朋友,让我们一起进步!
System V标准(又称System V IPC)是UNIX操作系统中的一组标准,定义了进程间通信(IPC)机制,旨在使不同UNIX系统之间的通信操作具有一致性。System V提供多种IPC机制,包括共享内存,消息队列,信号量等。
允许多个进程访问同一块物理内存区域。这是最有效的IPC机制,速度最快,因为数据不需要通过内核传递,而是直接在进程之间共享。
int shmget(key_t key, size_t size, int shmflg);
shmget 是在 System V 标准中用于获取共享内存段的系统调用。它的作用是创建一个新的共享内存段,或者打开一个已存在的共享内存段,并返回一个标识符,供后续操作使用。 参数:
返回值是共享内存的标识符(shmid),用于后续的操作。如果返回值是 -1,则表示发生错误。
注意上述的key值需要用户手动传入给内核:调用ftok()系统调用。
原型如下:
key_t ftok(const char *pathname, int proj_id);
pathname:指定一个存在的文件路径。该文件用作生成键值的基础。该路径必须存在,可以与当前的工作区不相关联。
proj_id:是一个单字节的项目标识符。它通常是一个字母或数字(范围为 0 到 255)。与文件路径结合,生成一个唯一的键值。
成功时,返回生成的唯一键值(key_t 类型)。该键值通常是一个整数。
失败时,返回 -1,并设置 errno。
因为创建的共享内存随内核,所以要手动删除,如果要删除共享内存,可以使用指令:
ipcrm -m [shmid值],注意:shmid不是key值,key只使用OS来识别的,而用户使用shmid来进行操作。
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:
int shmdt(const void *shmaddr);
返回值:
注意事项:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl 是一个用于控制共享内存段的 System V IPC 函数。通过 shmctl,你可以对共享内存段进行多种管理操作,如获取共享内存的状态、删除共享内存段等。它是对共享内存资源的高级管理工具。 参数:
<一> IPC_STAT:获取共享内存段的状态,并将信息存储在 shmid_ds 结构中。
<二> IPC_SET:修改共享内存段的权限或其他属性。
<三> IPC_RMID:删除共享内存段,标记该共享内存段为待删除。只有在所有进程都断开对该共享内存的连接后,内存段才会被系统回收。
示例代码:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
// 创建共享内存
int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget failed");
return -1;
}
// 获取共享内存的状态
struct shmid_ds shm_info;
if (shmctl(shmid, IPC_STAT, &shm_info) == -1) {
perror("shmctl IPC_STAT failed");
return -1;
}
// 打印共享内存信息
printf("Shared memory size: %zu bytes\n", shm_info.shm_segsz);
printf("Last attach time: %s", ctime(&shm_info.shm_atime));
// 删除共享内存
if (shmctl(shmid, IPC_RMID, NULL) == -1) {
perror("shmctl IPC_RMID failed");
return -1;
}
return 0;
}
在操作系统中,共享内存是进程间通信(IPC)的一种高效方式,因为它允许多个进程直接访问同一块内存区域,而不需要通过管道、套接字等其他通信机制。使用共享内存,服务端和客户端可以通过读写共享内存来交换数据。
功能:
示例代码:
#pragma once
#include <iostream>
#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include "comm.hpp"
const int defaultid = 1;
const int gsize = 4096;
const std::string pathname = ".";
const int projid = 0X66;
const int gmode = 0666;
#define CREATER "creater"
#define USER "user"
class Shm
{
private:
void CreateHelper(int flg)
{
printf("key: 0x%x\n", _key);
// 共享内存的生命周期,随内核
// shmget() 会失败(因为共享内存已存在),导致程序直接终止。
_shmid = shmget(_key, _size, flg);
if (_shmid < 0)
{
ERR_EXIT("shmget");
}
printf("shmid: %d\n", _shmid);
}
void Create()
{
CreateHelper(IPC_CREAT | IPC_EXCL | gmode);
}
void Attach()
{
_start_mem = shmat(_shmid, nullptr, 0);
if ((long long)_start_mem < 0)
{
ERR_EXIT("shmat");
}
printf("attach success\n");
}
void Detach()
{
int n = shmdt(_start_mem);//去关联系统调用
if (n == 0)
{
printf("detach success\n");
}
}
void Get()
{
CreateHelper(IPC_CREAT); // 不存在则创建;否则打开它,并返回
}
void Destory()
{
Detach();
if (_usertype == CREATER)
{
int n = shmctl(_shmid, IPC_RMID, nullptr);
if (n >= 0)
{
printf("shmcyl delete shm: %d success!\n", _shmid);
}
else
{
ERR_EXIT("shmctl");
}
}
}
public:
Shm(const std::string &pathname, int projid, const std::string &usertype)
: _shmid(defaultid),
_size(gsize),
_start_mem(nullptr),
_usertype(usertype)
{
_key = ftok(pathname.c_str(), projid); // 手动创建key值,用于让不同的进程看到一份资源(共享内存)
if (_key < 0)
{
ERR_EXIT("ftok");
}
if (_usertype == CREATER)
Create();
else if (_usertype == USER)
Get();
else
{
}
Attach();
}
void *VirtualAddr()
{
printf("VirtualAddr: %p\n", _start_mem); // 存在于堆栈区间的虚拟地址,堆栈之间的空间是共享区,
// 属于用户的空间,不需要用系统调用
// 共享内存是进程间通信最快的方式:原因1:映射之后直接被对方看到,原因2:不需要系统调用,花费额外的时间开销
return _start_mem;
}
int Size()
{
return _size;
}
void Attr()
{
struct shmid_ds ds;
int n =shmctl(_shmid, IPC_STAT,&ds);
printf("shm_segsz: %ld\n",ds.shm_segsz);
printf("key: 0x%x\n",ds.shm_perm.__key);
}
~Shm()
{
if (_usertype == CREATER)
Destory();
}
private:
int _shmid;
key_t _key;
int _size;
void *_start_mem;
std::string _usertype;
};
注意:该类主要用了实现数据的同步,防止数据不一致,同时当客户端端有数据时(wakeup函数)通知服务端读取(wait函数)数据,真正的数据存在共享内存中。 示例代码:
#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
#include <unistd.h>
#include <cstdio>
#include "comm.hpp"
#define PATH "."
#define FIFENAME "fifo"
class NameFifo
{
public:
NameFifo(const std::string &path, const std::string &name)
: _path(path), _name(name)
{
_filoname = _path + "/" + _name;
umask(0);
// 新建管道
int n = mkfifo(_filoname.c_str(), 0666);
if (n < 0)
{
ERR_EXIT("mkfifo");
}
else
{
std::cout << "mkfifo success" << std::endl;
}
}
~NameFifo()
{
// 删除管道文件
int n = unlink(_filoname.c_str());
if (n == 0)
{
//ERR_EXIT("unlink");
}
else
{
std::cout << "remove fifo failed" << std::endl;
}
}
private:
std::string _path;
std::string _name;
std::string _filoname;
};
示例代码:
class FileOper
{
public:
FileOper(const std::string &path, const std::string &name)
: _path(path), _name(name), _fd(-1)
{
_filoname = _path + "/" + _name;
}
void OpenForRead()
{
// 打开管道文件
_fd = open(_filoname.c_str(), O_RDONLY);
if (_fd < 0)
{
ERR_EXIT("open");
}
std::cout << "open fifo sucess" << std::endl;
}
void OpenForWrite()
{
// write
_fd = open(_filoname.c_str(), O_WRONLY);
if (_fd < 0)
{
ERR_EXIT("open");
}
std::cout << "open fifo success" << std::endl;
}
void Wakeup()
{
// 写入操作
char c = 'c';
int n = write(_fd, &c, 1);
printf("尝试唤醒: %d\n", n);
}
bool Wait()
{
char c;
int number = read(_fd, &c, 1);
if (number > 0)
{
printf("醒来: %d\n", number);
return true;
}
return false;
}
void Close()
{
if (_fd > 0)
close(_fd);
}
~FileOper()
{
}
private:
std::string _path;
std::string _name;
std::string _filoname;
int _fd;
};
通过共享内存和命名管道的协作,程序实现了一个高效的进程间通信机制。共享内存提供了高效的直接数据交换通道,而管道则充当了同步信号的角色,确保数据的可靠传输。
本文介绍了利用共享内存实现高效服务端-客户端通信的方法。共享内存作为进程间直接访问的内存区域,极大提升了数据传输效率,避免了传统IPC方式的数据拷贝开销。配合命名管道(FIFO)进行同步控制,服务端写入数据后通过管道发送唤醒信号,客户端阻塞等待信号后读取共享内存,确保数据一致性。Shm类封装了共享内存的创建、映射与销毁,FileOper类处理管道读写,二者协作实现了通知-读取的高效通信模式,适用于高频数据交换场景,兼顾性能与可靠性。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有