NodeSharp原理实现


  需求背景:公司产品是餐饮POS,使用的技术栈是 nw.js(一个带node执行环境的chrome壳子),需要对接很多硬件,但是很多硬件是只提供dll驱动,如果用nodejs的话是很难对接的,所以就引出这样的需求

  • 使用Edgejs

网上一般提供的方案一般是使用Edgejs,直接在js里执行C#代码 Edgejs 确实强大,示例代码如下:

var edge = require('edge'); 

var helloWorld = edge.func(function () {
/* async (input) => { return ".NET Welcomes " + input.ToString(); } */
}); 

helloWorld('JavaScript', function (error, result) { 
 if (error) throw error; 
 console.log(result); 
});

可以直接在js中写C#代码,也可以像这样,调用C#写的dll

	
    function loadDll(dllName){
         var dllImport = null;
	if(typeof(require) != 'undefined'){
		var edge = require('edge');
		dllImport = edge.func(dllName);
	}
	return dllImport;
};

对于dll有些要求,例如,我们的dll名称为 demo.dll,那么必须有个demo的namespace,然后这个namespace下必须有个Startup类,这个类还得有个 invoke公开方法 示例如下

namespace demo
{
    public class Startup
    {
        public async Task Invoke(dynamic data)
        {
           return await dosomething();
         }
    }
}

一切都很完美,直到有一天,来了个新需求,需要我们支持XP系统(很无奈,很多小店的确还在用XP的系统),注意上面的C#代码,使用了 async await,这个只在 .net4.5 开始支持,而 .net 4.5已经放弃对XP的支持,XP下最高只能安装 .net 4.0,心塞…

  •  使用子进程

这么好的解决方案用不了,只能想其他的办法了,首先想到的就是子进程,而且真的解决了我的问题,下面是自己的一点收获

  • 初级版

nodejs使用子进程的方式一般是这样的

     var spawn = require("child_process").spawn;
     var exepath = 'exe地址';
     var args=[];     
     var childprocess = spawn(exepath, args);

  信息传递的话,就是通过 上面的 args参数;那么C#中怎么获取参数呢?新建一个空的控制台项目,打开 Program.cs   对的,就是通过 Main函数的参数获取 我们可以通过传递不同的参数来控制C#执行不同的代码,那么执行完成后怎么把结果返回呢 很简单 直接Console.WriteLine 标准输出,那对于输出的结果又怎么获取呢? 也很简单,只要监听 子进程的 stdout的data事件,如下

childprocess.stdout.on('data', function (data) {
     console.log(data);
});
  •  高级版

上面是在程序运行之前就要确定需要传递的参数,所以功能有限,不够灵活,如果在exe已经运行的情况下,怎么进行数据交换呢? 先来看看,在nodejs中启动exe子进程后的对象是什么样的

 我们上面监听子进程输出用的是 stdout 这个Socket对象,这是一个只读的Socket,另外子进程对象还有个stdin,这是个只写的Socket,作用就是输入,对于这样的输入,C#中怎么获取呢? 上面C#输出用的是 Console.WriteLine 标准输出,所以,我们用标准输入就可以了,C#标准输入 是 Console.ReadLine

  • 终极版

至此,我们已经具备了所有与exe双向通讯的条件,但是如果只是简单的标准输入输出,很难与js配合处理复杂的业务场景,我们需要对这样的虚拟通道进行包装 以我们使用nw下的一个场景,node将sql语句发送给子进程exe,子进程执行sql,完成后将结果返回给node.

通过上面的方法,我们可以完成 node发送 ->  C#处理  ->  返回结果 主要流程都没有问题,但是我们的sql语句发送是连续的,就是node会一直发送,exe进行多线程处理,但是完成后返回的结果就懵逼了,谁跟谁啊,完全不知道执行的结果是谁需要的  

针对这个问题,我们可以抽象下,以我们熟悉的   浏览器->服务器 来类比下,node中每个发送给子进程的sql就相当于一个 浏览器,子进程就相当于服务器,只要我们给每个请求都给一个令牌,在子进程处理后,包装结果,把令牌也同时返回,node这边根据令牌找到相应的方法回调,至此所有问题解决,exe具备了作为node的服务的能力 相关解决方案及代码已开源

详见GitHub NodeSharp