nodejs与c语言交互应用实例
nodejs与c/c++交互目前主流的方式有两种,node addon c++ 和 node-ffi .
1、node addon c++
1)nodejs从c语言读取数据
addon.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> typedef struct { double lon; double lat; }gps_info_t; gps_info_t* gps; void get_gps_shm_init(void) { gps = (gps_info_t *)malloc(sizeof(gps_info_t)); } Napi::Object CreateObject(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); Napi::Object obj = Napi::Object::New(env); gps->lon = 55.5; gps->lat = 66.6; printf("send lon: %f\n", gps->lon); printf("send lat: %f\n", gps->lat); obj.Set(Napi::String::New(env, "lon"), gps->lon); obj.Set(Napi::String::New(env, "lat"), gps->lat); return obj; } Napi::Object Init(Napi::Env env, Napi::Object exports) { get_gps_shm_init(); return Napi::Function::New(env, CreateObject, "createObject"); } NODE_API_MODULE(addon, Init)
addon.js
var addon = require('bindings')('addon'); var obj = addon('gps'); console.log(obj.lon); console.log(obj.lat); module.exports.obj = obj;
2)nodejs向c语言写数据
addon.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> typedef struct { char *user_name; char *passwd; char *dev_id; }user_info_t; user_info_t* user; void put_user_info_shm_init(void) { user = (user_info_t *)malloc(sizeof(user_info_t)); user->user_name = (char*)malloc(32*sizeof(char)); user->passwd = (char*)malloc(32*sizeof(char)); user->dev_id = (char*)malloc(32*sizeof(char)); } Napi::Object CreateObject(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); Napi::Object obj = Napi::Object::New(env); memset(user->user_name, 0, 32); memset(user->passwd, 0, 32); memset(user->dev_id, 0, 32); memcpy(user->user_name, info[0].ToString(), 32); memcpy(user->passwd, info[1].ToString(), 32); memcpy(user->dev_id, info[2].ToString(), 32); printf("recv user info (user_name): %s\n", user->user_name); printf("recv user info (passwd): %s\n", user->passwd); printf("recv user info (dev_id): %s\n", user->dev_id); return obj; } Napi::Object Init(Napi::Env env, Napi::Object exports) { put_user_info_shm_init(); return Napi::Function::New(env, CreateObject, "createObject"); } NODE_API_MODULE(addon, Init)
addon.js
var addon = require('bindings')('addon'); var user_info = { user_name = 'zdd'; passwd = '123'; dev_id = '65535' } var obj = addon(user_info.user_name,user_info.passwd,user_info.dev_id); module.exports.user_info = user_info;
nodejs的C/C++拓展,将c/c++源码编译成js模板库
ubuntu下编译
node-gyp configure
node-gyp build
node addon.js
交叉编译
export CC=arm-linux-gnueabihf-gcc
export CXX=arm-linux-gnueabihf-g++
export LD=arm-linux-gnueabihf-ld
export RAINLIB=arm-linux-gnueabihf-rainlib
export AR=arm-linux-gnueabihf-ar
export LINK=arm-linux-gnueabihf-g++
node-gyp configure --arch=arm
node-gyp build
node addon.js
2、node-ffi
1)nodejs从c语言读取数据
factorial.c
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #if defined(WIN32) || defined(_WIN32) #define EXPORT __declspec(dllexport) #else #define EXPORT #endif typedef struct { double lon; double lat; }gps_info_t; gps_info_t* gps; void get_gps_shm_init(void) { gps = (gps_info_t *)malloc(sizeof(gps_info_t)); } EXPORT gps_info_t* get_gps_info(void) { get_gps_shm_init(); gps->lon = 55.5; gps->lat = 55.5;return gps; }
factorial.js
var ffi = require('../node-ffi-master/') var refStruct = require('ref-struct'); var refArray = require('ref-array'); var ref = require('ref'); //gps date struct var gps = refStruct({ 'lon':ref.types.double, 'lat':ref.types.double, }); var gpsStructArrayType = refArray(gps); var gps_info = gpsStructArrayType(10); var libfactorial = ffi.Library('./libfactorial', { 'get_gps_info': [ gpsStructArrayType, [ 'void' ] ], }); gps_info = libfactorial.get_gps_info(0) console.log('Your output: ' + gps_info[0].lon) console.log('Your output: ' + gps_info[0].lat)
2)nodejs向c语言写数据
factorial.c
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #if defined(WIN32) || defined(_WIN32) #define EXPORT __declspec(dllexport) #else #define EXPORT #endif typedef struct { char *user_name; char *passwd; char *dev_id; }user_info_t; user_info_t* user; void put_user_info_shm_init(void) { user = (user_info_t *)malloc(sizeof(user_info_t)); user->user_name = (char*)malloc(32*sizeof(char)); user->passwd = (char*)malloc(32*sizeof(char)); user->dev_id = (char*)malloc(32*sizeof(char)); } EXPORT void put_user_info(user_info_t* user_info) { put_user_info_shm_init(); printf("get userinfo(user_name):%s",user_info->user_name); printf("get userinfo(user_name):%s",user_info->passwd); printf("get userinfo(user_name):%s",user_info->dev_id); }
factorial.js
var ffi = require('../node-ffi-master/') var refStruct = require('ref-struct'); var refArray = require('ref-array'); var ref = require('ref'); //ui date struct var user = refStruct({ 'user_name':'string', 'passwd':'string', 'dev_id':'string', }); var userStructArrayType = refArray(user); var user_info = userStructArrayType(1); user_info[0].user_name = 'zdd'; user_info[0].passwd = '123'; user_info[0].dev_id = '65535'; var libfactorial = ffi.Library('./libfactorial', { 'put_user_info': [ 'void', [ userStructArrayType ] ] }); libfactorial.put_user_info(user_info) console.log('Your input: ' + user_info[0].user_name) console.log('Your input: ' + user_info[0].passwd) console.log('Your input: ' + user_info[0].dev_id)
gcc / arm-linux-gnueabihf-gcc -shared -fpic factorial.c -o libfactorial.so
node factorial.js
上面两种方式写了个demo放在github上了
https://github.com/zhoudd1/nodejs_call_c_cc
3、还有一种小众化的方式
通过child_process 方式调用EXE进程来实现数据交互。
//同步的方式
letout = cp.execFileSync("testdll.exe", ["arg1","arg2"],{});
//异步的方式
console.log(stdout);
})
这种方式NODE 会接管stdout 和 stderr ,exe中把结果通过 printf 输出。
缺点:需要先生成EXE,EXE 中调用 DLL/so 并且返回结果。
优点:不需要配置 FFI,不受DLL/so 的影响
更多细节
https://www.cnblogs.com/chyingp/p/node-learning-guide-child_process.html
https://blog.csdn.net/zeping891103/article/details/52230175