作者: JeremyWei | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明
网址: http://it.taocms.org/01/2540.htm.html

介绍

Node(或者Node.js)作为一门新兴的技术已经被越来越多的企业所使用,事件驱动的开发模式也为服务器端的开发注入了新的力量,Node很容易上手,只要你拥有JavaScript的基础和服务器端的开发经验。Node为开发者提供了两种方式来对其进行扩展:一种是通过JavaScript,一种是通过C/C++。在Node中使用JavaScript来编写模块是非常容易,也是最常用的方式,但是在一些场景中JavaScript的执行性能可能达不到要求(比如大量的位运算),不用发愁,Node还提供了C++的模块扩展接口,以提高执行的性能,本文就简要介绍下Node中C++模块的开发。

目标

本文我们创建一个名为hello的模块,其包含一个名为sayHello的方法,如果用JavaScript来表示的话,可能是这样:

exports.sayHello = function() {
    return "Hello World!";
}

概念

Node的JavaScript引擎用的是Google开源的V8 JavaScript引擎(Chrome浏览器所用的引擎),所以简单介绍下v8中的一些概念:

1 Handle:一个handle就是指向一个对象的指针。v8中所有的对象都是使用handle来进行访问,之所以用它是因为v8的垃圾回收器需要。

2 HandleScope:可以把它想象成是多个Handle的一个容器。

除了v8之外,这里还要说明一下,用C++编写的模块和用JavaScript编写的模块在使用方式上并无区别,都是通过require(...)来进行调用,区别在于C++模块是系统编译好的二进制模块(在*nix下是.so,在win下是dll),并且扩展名为.node。在require.node模块的时候,系统通过dlopen函数来加载模块,不需要像JavaScript模块那样再进行编译,而是直接加载运行,这加快了执行的速度。

编写

首先创建模块需要的目录src和源文件hello.cc

$ mkdir -p hello/src && cd hello/src
$ touch hello.cc

hello.cc的内容如下:

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

// 引入v8命名空间
using namespace v8;

// sayHello方法的具体逻辑
Handle<Value> Method(const Arguments& args) {
    HandleScope scope;
    // 返回一个"Hello World!"字符串
    return scope.Close(String::New("Hello World!"));
}

// 初始化模块
void init(Handle<Object> target) { 
    // 定义模块中的sayHello方法
    NODE_SET_METHOD(target, "sayHello", Method);
}

// 定义"hello"模块
NODE_MODULE(hello, init);

以上就是模块的所有代码,还是比较容易理解的,其中的NODE_SET_METHOD和NODE_MODULE是node.h中定义的宏,具体如下:

Node模块的数据结构定义:

struct node_module_struct {
  int version;
  void *dso_handle;
  const char *filename;
  node::addon_register_func register_func;
  node::addon_context_register_func register_context_func;
  const char *modname;
};

NODE_SET_METHOD定义:

template <typename TypeName>
inline void NODE_SET_METHOD(const TypeName& recv,
                            const char* name,
                            v8::FunctionCallback callback) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::HandleScope handle_scope(isolate);
  v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(callback);
  v8::Local<v8::Function> fn = t->GetFunction();
  v8::Local<v8::String> fn_name = v8::String::NewFromUtf8(isolate, name);
  fn->SetName(fn_name);
  recv->Set(fn_name, fn);
}

NODE_MODULE定义:

#define NODE_MODULE(modname, regfunc)                                
   extern "C" {                                                       
     NODE_MODULE_EXPORT node::node_module_struct modname ## _module = 
     {                                                                
       NODE_STANDARD_MODULE_STUFF,                                    
       (node::addon_register_func) (regfunc),                         
       NULL,                                                          
       NODE_STRINGIFY(modname)                                        
     };                                                               
   }

更加详细的内容,可以查看Node的源码。

编译

Node为了实现跨平台的编译,采用了Google的GYP(Generate Your Projects)来对项目进行管理。为了能够编译我们的项目,我们需要安装node-gyp:

$ npm install -g node-gyp

安装完成之后,进入到源码目录,并且创建binding.gyp文件,因为binding.gyp是默认的项目定义文件。

$ cd hello
$ touch binding.gyp

并且binding.gyp的内容为:

{
  'targets': [
    {
      'target_name': 'hello',
      'sources': [
        'src/hello.cc'
      ],
      'dependencies': [
      ]
    }
  ]
}

之后我们以binding.gyp文件来生成Makefile等编译所需的文件:

$ node-gyp configure

执行完成之后,在项目目录下会生成一个build目录,里边是gyp自动生成的一些编译所需文件。这一步完成之后,我们来进行编译操作:

$ node-gyp build

如果执行没有问题的话,在build/Release目录下会生成hello.node文件,即我们创建的hello模块。

运行

模块编译成功之后,我们来测试测试模块的功能。在项目目录下创建一个test.js文件,内容如下:

var hello = require('./build/Release/hello.node');
console.log(hello.sayHello());

执行此文件

$ node test.js
$ Hello World!

总结

本文简要介绍了Node中C++模块的开发方式,v8中Handle和HandleScope的概念,以及gyp工具的使用,并实现了一个hello扩展模块。本文部分内容来自于《深入浅出Node.js》。

更多内容可以查看Node源码: 
https://github.com/joyent/node/blob/master/src/node.h 
https://github.com/joyent/node/blob/master/src/node.cc

转载于:https://blog.51cto.com/snaile/1672161

动手编写Node的C++模块相关推荐

  1. node.js中模块_在Node.js中需要模块:您需要知道的一切

    node.js中模块 by Samer Buna 通过Samer Buna 在Node.js中需要模块:您需要知道的一切 (Requiring modules in Node.js: Everythi ...

  2. 第二章. node中的模块和require

    2019独角兽企业重金招聘Python工程师标准>>> 一 什么是模块. JavaScript诞生初,它只不过是一个网页的小脚本而已,没有人会想到它会发展到现在能有大量的库,工具,组 ...

  3. Node.js:模块查找,引用及缓存机制

    1. Node.js的模块载入方式与机制 Node.js中模块可以通过文件路径或名字获取模块的引用.模块的引用会映射到一个js文件路径,除非它是一个Node内置模块.Node的内置模块公开了一些常用的 ...

  4. Node对CommonJS模块的实现

    在Node中,每个文件模块都是一个对象,它的定义如下: function Module(id, parent) { this.id = id; this.exports = {}; this.pare ...

  5. Rust: 基于 napi-rs 开发 Node.js 原生模块

    Rust: 基于 napi-rs 开发 Node.js 原生模块 文章目录 Rust: 基于 napi-rs 开发 Node.js 原生模块 完整代码示例 背景 & napi 环境/工具链准备 ...

  6. Node学习HTTP模块(HTTP 服务器与客户端)

    Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...

  7. python反编译luac_Lua程序逆向之为Luac编写IDA Pro处理器模块

    上一篇讲解了如何加载一个Luac文件到IDA Pro当中,加载进入idb数据库的内容犹如切好洗净的食材,并不能粗暴的直接展示给用户,还需要IDA Pro中的处理器模块对内容进行下一步的反汇编渲染与指令 ...

  8. Node 入门及模块系统

    初识Node.js与模块 ◆ 能够知道什么是 Node.js ◆ 能够知道 Node.js 可以做什么 ◆ 能够说出 Node.js 中的 JavaScript 的组成部分 ◆ 能够使用 fs 模块读 ...

  9. JavaScript之后端Web服务器开发Node.JS基本模块学习篇

    JavaScript之后端Web服务器开发Node.JS基本模块学习篇 基本模块 fs文件系统模块 stream支持流模块 http crypto加密模块 基本模块 因为Node.js是运行在服务区端 ...

最新文章

  1. 对象----《你不知道的JS》
  2. if(a==1且a==2且a==3),有没有可能为true?
  3. R语言条件Logistic回归模型案例:研究饮酒与胃癌的关系
  4. WebService简单开发 apache-cxf-3.1.6环境配置
  5. win10便签常驻桌面_win7桌面便签小工具可以作为工作计划软件使用吗?
  6. Javascript中的\r\n
  7. 计算机一级资料书推荐,推荐版 全国计算机一级考试试题【史上最全面的资料,不看你就亏!】.doc...
  8. php连贯操作,Thinkphp 3.2.3 sql的一些连贯操作方法
  9. 2020 年百度之星·程序设计大赛 - 复赛 1001Battle for Wosneth
  10. python的作用域分别有几种_Python中作用域的深入讲解
  11. NET中的三种Timer的区别和用法
  12. (5)数据结构-栈顺序存储
  13. Python对象转json【包括嵌套对象转json,django的model转json】
  14. 国外免费数据集下载网址
  15. 软件性能测试操作系统,优秀的系统性能测试软件Sisoft Sandra
  16. python识别图形形状
  17. oracle升序和降序同时存在,oracle升序排序 oracle升序和降序
  18. Vite图片压缩(vite-plugin-imagemin) imagemin error: XXXX解决办法
  19. 推荐电影 迪士尼经典动画片大全 1937-2008
  20. 使用神经网络中的卷积核生成语谱图

热门文章

  1. 20190903:(leetcode习题)颠倒二进制位
  2. 微型计算机原理及应用程序题,微型计算机原理及应用试题及答案
  3. javax maven项目缺少_maven冲突解决流程
  4. wpf window 不执行show 就不能load执行_关于机器学习中的Scikit-Learn,你不知道的10个实用功能...
  5. BUS HOUND调试USB驱动遇到的错误代码解析
  6. Zigbee 学习计划——第2天——熟悉CC2530的基本例程
  7. Redis实现计数器---接口防刷
  8. jmeter学习指南之Beanshell Sampler 常用方法
  9. MongoDB3.4为单独的数据库创建用户
  10. 创意对抗网络(CANs)你知多少?