Node.js 调用C++库

Node.js 调用C++库

    • 前言
      • 调用方法和使用技巧
      • Buffer类
      • 常用的buffer方法:
        • Buffer.alloc(size[, fill[, encoding]])
        • Buffer.from(array)
        • Buffer.from(buffer)
        • Buffer.from(string[, encoding])
      • 相关库介绍
      • C++ enum(枚举) 转JavaScript 对象
      • 导出函数
        • ref 中常用的方法
        • 内置简写
      • 参考资料

前言

使用Node.js去调用C++的库,整理了一些相关资料,方便以后开发少走些弯路。希望对大家也有所帮助。

调用方法和使用技巧

文章主要内容:
https://juejin.im/post/5b58038d5188251b186bc902
本文是对上文的一个补充。

Buffer类

在 ECMAScript 2015 引入 TypedArray 之前,JavaScript 语言没有读取或操作二进制数据流的机制。 Buffer 类被引入作为 Node.js API 的一部分,使其可以在 TCP 流或文件系统操作等场景中处理二进制数据流

TypedArray 现已被添加进 ES6 中,Buffer 类以一种更优化、更适合 Node.js 用例的方式实现了 Uint8Array API。

Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整。

Buffer 类在 Node.js 中是一个全局变量,因此无需使用 require('buffer').Buffer

常用的buffer方法:

Buffer.alloc(size[, fill[, encoding]])

  • size <integer> 新建的 Buffer 期望的长度
  • fill <string> <Buffer> | <integer> 用来预填充新建的 Buffer 的值。 默认: 0
  • encoding <string> 如果 fill 是字符串,则该值是它的字符编码。 默认: ‘utf8’
    分配一个大小为 size 字节的新建的 Buffer 。 如果 fill 为 undefined ,则该 Buffer 会用 0 填充。

Buffer.from(array)

新增于: v5.10.0

  • array <Array>
    通过一个八位字节的 array 创建一个新的 Buffer 。
// 创建一个新的包含字符串 'buffer' 的 UTF-8 字节的 Buffer
const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);

如果 array 不是一个数组,则抛出 TypeError 错误。

Buffer.from(buffer)

新增于: v5.10.0

  • buffer <Buffer> 一个要拷贝数据的已存在的 Buffer
    将传入的 buffer 数据拷贝到一个新建的 Buffer 实例。

例子:

const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1);

buf1[0] = 0x61;

// 输出: auffer
console.log(buf1.toString());

// 输出: buffer
console.log(buf2.toString());

如果 buffer 不是一个 Buffer,则抛出 TypeError 错误。

Buffer.from(string[, encoding])

新增于: v5.10.0

  • string <string> 要编码的字符串
  • encoding <string> string 的字符编码。 默认: ‘utf8’
    新建一个包含所给的 JavaScript 字符串 string 的 Buffer 。 encoding 参数指定 string 的字符编码。

例子:

const buf1 = Buffer.from('this is a tést');

// 输出: this is a tést
console.log(buf1.toString());

// 输出: this is a tC)st
console.log(buf1.toString('ascii'));


const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');

// 输出: this is a tést
console.log(buf2.toString());

如果 string 不是一个字符串,则抛出 TypeError 错误。

相关库介绍

npm install ffi    
npm install ref
npm install ref-array
npm install ref-struct

1.ffi是调用dll动态链接库模块
2.ref扩展了内置的Buffer类,有助于JavaScript进行C编程
3.ref-array 在Buffers之上提供C类型的数组
4.ref-struct 在Buffers之上提供了符合ABI的struct(结构体)实例

C++ enum(枚举) 转JavaScript 对象

C++ enum

  enum Color = {
	  RED, 
	  GREEN, 
	  BLUE
  };
  

方式1:

var Color = {
    RED: 0,
    GREEN: 1,
    BLUE: 2
}
if (Object.freeze) Object.freeze(Color);
//或者使用ES6
const Color = {
    RED: 0,
    GREEN: 1,
    BLUE: 2
}
if (Object.freeze) Object.freeze(Color);

方式2

var Color;
if(Color || (Color={})){
    Color[Color["RED"] = 0] = "RED";
    Color[Color["GREEN"] = 1] = "GREEN";
    Color[Color["BLUE"] = 2] = "BLUE";
}
if (Object.freeze) Object.freeze(Color);

导出函数

引用的库

var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');
var refArray = require('ref-array');

函数导出

ffi.Library('要调用的dll', {
   '函数名': ['函数返回值类型', ['函数形参1', '函数形参2'], 
})
//这里的 '函数名' 要跟库中的 '函数名' 保持一致.

ref 中常用的方法

  • ref.types.xxx
    在JavaScript中生成C++中对应的基本类型(http://tootallnate.github.io/ref/#types)

  • ref.refType(Object | String type )
    生成C++中对应的指针,例如生成int类型的指针:ref.refType(ref.types.int)

  • ref.ref(Buffer buffer)
    接受一个Buffer实例并返回一个新的Buffer实例,该实例的大小为“指针”的大小,其数据指向给定的Buffer实例。基本上,创建的Buffer是原始指针的“引用”,相当于以下C代码:

    char *buf = buffer;
    char **ref = &buf;
    
  • ref.deref(Buffer buffer)
    返回:解除引用 Buffer 后返回的值。
    接受一个Buffer实例并尝试“dereference(解引用/解除引用/反引用)”它。也就是说,首先它检查 buffer “类型” 的indirection(解除引用)计数,如果它大于1,那么它只返回另一个Buffer,同时减少一级的indirection。
    当Buffer的indirection值为1时,它会检查buffer.type ,buffer.type应该是一个自己具有get()函数的对象。

    var buf = ref.alloc('int', 6);
    var val = ref.deref(buf);
    console.log(val);
    //6
    

内置简写

ffi中内置了一些简写

ref.types.int => 'int'
ref.refType('int') => 'int*'
char* => 'string'

调用例子:

var dll = ffi.Library( './test.dll', {
    Fun1: ['int', ['string', 'int', 'int']], 
    Fun2: [ref.types.void, ['string', ref.types.int]]
})

如果返回值是一个指针的话,则需要先定义一个指针:

//C++的结构体:
struct 
{
    int a;
    char b;
    double c;
} s1;

//JavaScript中的结构体
var s1=Struct({
	a:'int',
	b:ref.types.char
	c:ref.types.double
})

然后再导出函数:

var dll = ffi.Library( './test.dll', {
    Fun1: [ref.refType(s1), ['string', 'int', 'int']], 
})

参考资料

http://tootallnate.github.io/ref/
http://hax.iteye.com/blog/159332
https://en.wikipedia.org/wiki/Indirection
https://nodejs.org/api/buffer.html#buffer_buffer
https://juejin.im/post/5b58038d5188251b186bc902
https://stijndewitt.com/2014/01/26/enums-in-javascript/

你可能感兴趣的:(Node.js)