重新买了个笔记本,博客荒废了快2年,又可以在家写了。
最近使用NodeJS的C++插件写了一个简单NodeJS Http服务器,将学习和编写过程记录一下。本文只有思路步骤代码,并不提供完整demo
- 需求:服务器端生产音视频裸流 => 封装flv流 => 推送流
- 思路:1.对于不熟后台的人,NodeJS可以快速搭建服务器;2.部分现有代码是由C、C++实现的,代码需要多线程运行,所以用C++插件来封装给JS调用。
1、开发环境配置:
安装node-gyp:
npm install -g node-gyp
在工程目录下编写 binding.gyp 文件:
1 | { |
使用npm init生成package.json文件
package.json 里面添加:”gypfile”: true
添加bindings(用于解决C++插件位置的定位问题)组件依赖:
npm install bindings —save
生成插件xxx.node:
node-gyp configure
然后node-gyp build
(后面c++文件修改后,使用node-gyp rebuild
来合并使用者2个命令)生成xcode debug工程来进行代码调试:
node-gyp configure -- -f xcode
打开xcode工程:Product -> Scheme -> Edit Scheme,Info -> Executable -> Other,选择node所在位置,例如我的在:/Users/cooperchen/.nvm/versions/node/v8.10.0/bin/node
Arguments选项中Atruments Passed On Launch中点击加号,将调试入口的JS文件拖进去。
这样就可以在xcode中用node来运行app.js了。使用xcode调试的好处是,调整完插件代码,可以直接运行,不需要每次都输入
node-gyp rebuild
命令,然后再用node启动服务器
一些小技巧:
在
npm install
的时候可以同时build插件,编辑package.json
1
2
3"scripts": {
"install": "node-gyp rebuild",
},在添加新的C、C++源文件后,不需要手动添加到
binding.gyp
的懒人方法,编辑binding.gyp
1
2
3
4//假设现在所有c、c++源文件都在 binding.gyp 文件所在目录的./source文件夹里面
"sources": [
"<!@(node -p \"require('fs').readdirSync('./source').map(f=>'source/'+f).join(' ')\")",
],
2、插件实现:
- 代码调用过程:JS调用一个函数注册一个回调,在某些时候这个回调被调用。
- 在练手的时候,用NodeJS插件封装了一下
live555
这个C++库,用音频数据获取来做示例,播放端在JS层是这么调用的:
1 |
|
- 注册插件(C、C++实现)
1 |
|
- 注册回调
1 |
|
- 触发回调
1 |
|
- libuv的使用
上面实现了:JS层注册回调 => C++处理数据并从回调函数中传递数据到JS层 => JS层从回调函数中收到数据
但是上面都是在主线程中实现的,如果想要在子线程中处理完数据,在主线程中回调到JS中,就需要使用libuv
1 |
|
到目前为止,上述思路基本可以满足一个简单完整插件的需求:子线程处理数据,然后主线程回调到JS层
3、一些理解
- 插件开发主要是
V8引擎
和libuv
配合使用 - v8引擎由于版本变动api兼容性差,基本推荐使用
NAN
方案来解决兼容性问题 - v8 api的调用(或者说NAN api的调用 )基本上可以说是模板式的调用,如果不需要去看NodeJS的源码的话,使用的时候基本是复制粘贴的模式,只需要了解它基本的类结构,主要精力放在写自己的C、C++逻辑就好。
- libuv提供了消息机制,线程、网络、文件等api。
- 对于libuv,它解决了如windows,linux等不同平台的api兼容性问题。如果你的同事用windows机器,你用mac机器来开发同一个插件的时候,在开发的时候尽量使用它提供的api,如线程、网络等。
4、资料与学习
整理了一下资料的学习顺序,所有资料都是必看。
gyp文件配置字段 (按需查找使用)
gyp用户手册 (按需查找使用)
NodeJS C++插件开发方式演进 (理解为什么使用Nan来写插件)
C++插件demo,含V8原生使用方式和NAN使用方式 (可以抄代码的地方)