如何从Node.js调用C++代码?

24

我目前正在开发一款运行在服务器上,在浏览器中显示数据的模拟器。

为了提供文件服务、通讯等功能,我想使用Node.js。但是,我不确定它在计算方面是否能够表现出我所期望的性能,因此我想用C++来开发模拟部分。

这个模拟器被划分为几个不同的“世界”,每个世界都有一些初始参数。

最佳的方式是什么?


也许最简单的方法是从node.js分叉C程序,然后有一个回调函数来收集它的输出。 - Paul
你有进行基准测试吗?只是说,V8(node后面的JavaScript引擎)即使对于计算密集型操作也可以非常快,我认为在转向C/C++之前应该确切地检查它的性能表现。 - Mahn
虽然听起来更像是你在考虑想要选择哪种编程语言。在这种情况下,我建议保持一门语言。如果可以避免使用两种语言,为什么要使用两种语言呢? - Paul
我只是觉得我正在使用一个网络服务器框架进行科学研究(计划将其提交到一些比赛中),这不是Node的本意。 - corazza
是的,我已经基本决定了。我会将模拟引擎作为C++中的独立类,并通过脚本运行它,可以选择Python或Node.js(可能是Node.js)。 - corazza
请大家注意,看一下澄清。 - corazza
1个回答

47

V8允许从JavaScript调用C++代码。

因此,您的代码可以分为3个部分:

  • 正常的C++代码,不了解node.js和V8。这就是World所在的地方。
  • Glue node.js/V8-C++代码,使JS能够“看到”您的World类的部分。
  • 正常的JavaScript代码,通过“glue”层与C++代码进行通信。

首先,了解V8和C++之间的通信方式。Google提供了一个指南:https://developers.google.com/v8/embed

然后,您需要node.js特定的glue。请参见http://www.slideshare.net/nsm.nikhil/writing-native-bindings-to-nodejs-in-chttp://syskall.com/how-to-write-your-own-native-nodejs-extension

来自上面的slideshare链接:

#include <v8.h>
#include <node.h>

using namespace v8;

extern "C" {
   static void init(Handle<Object> target) {}
   NODE_MODULE(module_name, init)
}
我们可以将其扩展为更接近您想要的内容:

src/world.h

#ifndef WORLD_H_
#define WORLD_H_

class World {
    public:
        void update();
};

extern World MyWorld;

#endif

src/world.cpp

#include "world.h"
#include <iostream>

using std::cout;
using std::endl;

World MyWorld;

void World::update() {
    cout << "Updating World" << endl;
}

src/bind.cpp

#include <v8.h>
#include <node.h>
#include "world.h"

using namespace v8;

static Handle<Value> UpdateBinding(const Arguments& args) {
    HandleScope scope;

    MyWorld.update();

    return Undefined();
}

static Persistent<FunctionTemplate> updateFunction;

extern "C" {
   static void init(Handle<Object> obj) {
      v8::HandleScope scope;

        Local<FunctionTemplate> updateTemplate = FunctionTemplate::New(UpdateBinding);

        updateFunction = v8::Persistent<FunctionTemplate>::New(updateTemplate);

      obj->Set(String::NewSymbol("update"), updateFunction->GetFunction());
   }

   NODE_MODULE(world, init)
}

演示/演示.js

var world = require('../build/Release/world.node');
world.update();
是一个Microsoft Windows脚本宿主环境,允许使用VBScript和JScript编写脚本程序,并且可以与操作系统和其他应用程序进行交互。
def set_options(opt):
  opt.tool_options("compiler_cxx")

def configure(conf):
  conf.check_tool("compiler_cxx")
  conf.check_tool("node_addon")

def build(bld):
  obj = bld.new_task_gen("cxx", "shlib", "node_addon") 
  obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
  # This is the name of our extension.
  obj.target = "world"
  obj.source = "src/world.cpp src/bind.cpp"
  obj.uselib = []

在Linux shell中,需要进行一些设置:

node-waf configure

要构建,请运行:

node-waf

测试:

node demo/demo.js

输出:

Updating World

@Bane 请记住,大多数与node.js相关的函数都是基于回调的。我编写的方式中,“update()”将是一个阻塞同步函数,这可能对您来说是问题,也可能不是问题。 - luiscubal
+1 这很酷,我不知道还有这些自定义粘合层。 - Mahn
另外需要警告的是:此代码已在稳定版本的Node上进行了测试,但最新的不稳定版本将无法工作,因为v8发生了重大变化。 - luiscubal
这在2016年和现代的Node(v6等)中仍然是最佳解决方案吗?它看起来仍然相关,但为了确认我还是要检查一下。 - Majster
@Majster 不确定,但可能不是因为2013年的不稳定版本已经有所不同。 - luiscubal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接