Windows 下 QT 进程与 Node.js 进程通过共享内存通信

QT 进程共享内存可以借助 QT 提供的 QSharedMemory​​ 类实现,其是跨平台的。在 Windows 下,其基于 Windows File Mapping 技术实现内存共享。

NodeJS 进程需要通过编写 Addon(插件)的方式来访问 Window File Mapping API。编写 NodeJS Addon(插件)需要借助 node-addon-api 技术。

有关 Window File Mapping API,微软官方提供了 创建命名的共享内存 - Microsoft Learn 简单示例。

1 QT 写进程


#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
#include <cstring>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建 QSharedMemory 实例
    QSharedMemory sharedMemory;
    // 注意:设置本地 KEY
    sharedMemory.setNativeKey(QString::fromUtf8("MyTestSharedMemory"));
    // 创建共享内存,会自动调用 attach()
    if (!sharedMemory.create(1024, QSharedMemory::ReadWrite)) {
        qDebug() << "created failed";
        return -1;
    }
    qDebug() << "created successfully";
    // 绑定共享内存
    if (!sharedMemory.isAttached()) {
        qDebug() << "attached failed";
        return -1;
    }
    qDebug() << "attached successfully";

    // 定时写入动态数据
    QTimer timer;
    int count = 0;
    QObject::connect(&timer, &QTimer::timeout, [&]() {
       QString msg("hello data from shared memory!, index: ");
       msg.append(QString::number(count));
       const char * data_shm = msg.toStdString().c_str();
       // 向共享内存写入数据
       std::memcpy(sharedMemory.data(), data_shm, std::strlen(data_shm) + 1);
       qDebug() << "write data: " << data_shm;
       count += 1;
    });

    timer.start(1000); // 每秒更新一次

    return a.exec();
}

⚠️ 注意

由于此需求需要 QT 进程与 Node.js 进程通过共享通信,属于 QT 进程与非 QT 进程的交互场景,在创建 QSharedMemory​ 实例后,需要通过 setNativeKey()​ 方法设置本地 KEY。

2 Node.js 读进程


2.1 Node.js 读进程

node-filemap-buf Gitee 项目,其基于 node-addon-api 编写插件,通过调用 Window File Mapping 的 API 实现进程间内存共享。

  1. node-filemap-buf 项目克隆下来。将 node-filemap-buf\addon​ 目录下 addon.cc​、binding.gyp​、filemap.cc​、filemap.h​ 拷贝到你的 Node.js 工程根目录下。
  2. 使用 npm install -g node-gyp​ 命令全局安装 node-gyp​ 编译工具。
  3. 使用 npm install node-addon-api​ 命令本地安装 node-addon-api​ 依赖库
  4. 使用 node-gyp configure​ 命令配置工程,会生成 build​ 目录
  5. 使用 node-gyp build​ 编译工程,编译完成,会在 build/Release​ 目录下生成 addon.node​ 模块。

使用 build/release/addon.node​ 模块编写 Node.js 读进程代码:

var addon = require('./3rd/addon')
 
var mapName = "MyTestSharedMemory";
var bufSize = 1024;
var fileMap = new addon.FileMap();
 
var buf = fileMap.open(mapName,bufSize,0);
if(buf)
{
   console.log(`buf size=${buf.length}`);
   console.log(new String(buf));
}

2.2 Electron 读进程

过程完全参考 2.1 Node.js 读进程,但是对 node-filemap-buf 中的 filemap.cc​ 代码需要进行一点点修改,从而兼容 Electron 环境。

​filemap.cc​ 中

Napi::Value FileMap::create(const Napi::CallbackInfo& info)
{
   ...
   return Napi::Buffer<char>::New(env,(char*)pBuf, bufSize);
}

Napi::Value FileMap::open(const Napi::CallbackInfo& info)
{
   ...
   return Napi::Buffer<char>::New(env,(char*)buffer, bufSize);
}

的 return​ 语句与 Electron 不兼容。错误原因为:Napi::Buffer::New​ 方法直接将共享内存的指针暴露给 JavaScript。这种方式在标准 Node.js 环境中可能有效,但在 Electron 的 Node.js 环境中,外部缓冲区的管理受到限制,尤其是涉及共享内存时。

Electron 的 Node.js 环境可能会拒绝外部缓冲区的使用,因为它无法保证共享内存的生命周期和安全性。

为了解决上述问题,需要将 return​ 语句替换成:

// 创建一个新的缓冲区并复制数据
Napi::Buffer<char> resultBuffer = Napi::Buffer<char>::Copy(env, buffer, bufSize);

return resultBuffer;

参考链接:nodejs如何实现基于window File Mapping的进程间通信(IPC)_node addon发送ipc-优快云博客 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值