跳到主要内容

nodejs 通讯在工作中的思考和改进

· 阅读需 20 分钟

这篇文章也算是 nodejs 通讯在工作中的思考和改进吧,记录和分享下期中的体会和思路。

从最先开始的一个光 Socket Server,到现在的 Socket+websocket,其中经过了不少的变化与调整。

阶段一

最开始,紧紧是一个用于接收远端设备传送数据的 Socket 服务器,在这个阶段的代码也是很乱的,基本上所有的实现是以流水账的形式来走了一遍,基本可以满足了现有的需求,由于数据是按照了环保局的 212 通信协议来约定发送的,也让解析的阻力减小了不少,但是从总体代码来看,问题还是挺多的。

稍微列举下我能想到的:

复用性

软件写出来的目的就是为了尽可能的复用,从而简化了工作,从这方面一想,噢,我这时候实现的数据解析基本就是根据当前解析的一些特定数据来实现的,那么问题来了。

如果在这基础之上,又加入了新的数据,怎么办?找目前的情况来看,绝壁是要额外添加实现一遍解析的过程,那肯定是不好的。

扩展性

就像我上面说到的,整个过程都是耦合度很高的,相互都不能剥离,一步接着一步,这样的话,以后想在现有的通讯之上进行扩展,那是相当的麻烦。

分布式(横向扩展)

可能很多设计的比较好的系统来说,他们的瓶颈可能只是服务器的硬件或者是环境因素导致,这个时候只是额外的加入节点就可以解决性能问题,如果是这样的话,那就是最好的。

就我目前的项目来说,都还没往这方面考虑。

阶段二

然后,我第一次比较大的改动是,首先将各个功能划分的更细,分成了一些所谓的“功能模块”出来,database、handler、receive、messagequeue 等等这些。

是的,确实清晰多了,看上去好像各有各的分工。

差不多这时候也就是到了第二个项目,仍然是采用 nodejs 作为通讯服务器,沿用之前的架子吧,这次优化了一些东东:

  1. 项目中能做成配置文件的东西尽量不直接硬编码到代码中。
  2. 加入了一些日志调试信息。
  3. 所有日志打印的一些调试信息都被封装到一个消息字典里,而且还很自大的取了个名字叫 lang_zh_CN,哈哈,就算没有国际化的水平也要有一颗国际化的心嘛(万一实现了呢)。
  4. 解析部分,我是根据了 212 协议中各个区段的特点大概的封装了一下将数据用正则表达式的方式直接就替换+组装转化成 JSON 字符串,我想这应该比之前先循环的切分,再一个个组装到对象中要来的快(总体来说就是个嵌套循环) ,我老早就想优化,只是因为之前那个版本原本是从 java 的原始版本复制成的 nodejs 版本,所以并未做很大的改动,另一方面也是项目催的急根本没时间考虑这些个因素,可能前面的项目中的通讯会成为以个历史遗留问题吧,可能以后在系统的设计上要考虑到将原先的系统接入进来的可能性了。

阶段三

恩,再有就是现在的通讯加入了另一方面的需求,就是在 J2EE 的 web 系统中通过调用通讯端的接口来实现反控现场设备,那么这就涉及到了 HTTP 这一块。

由于之前我自己嫌那个破 Socket Server 太坑爹,每次看有没有错误都要连到服务器去把日志翻出来看,所以我一不爽就给他加入了个 web server(基于 express),上面显示当前服务器的连接数啊、接收数据包成功 / 失败数啊、入库的成功 / 失败数啊、错误数据的数据包内容列表啊、还有个 highchart 画的曲线图包括了包速率和丢包率(其实灵感来自于阿里云的控制台)。

这个设备反控的实现跟上面的 webserver 还是有点关系的,我由于做了周期性的统计当前数据接收入库等情况,而且显示到页面上来,难道我要不停的去刷新查询?

我有这么勤快么,我自己都不信,然后我就想起来之前的一个模块叫 socket.io 的,咋一看名字还以为是 socket,其实啊,它是 websocket 实现(HTML5 中出现的双工通信协议),然后一看,居然 IE8 也有 ajax 的封装实现,不错,就它了,于是就愉快的推送起服务端的数据通信状态了。

回到设备反控,也就是在 J2EE 系统这边引用了我的 socket.io 的客户端 js 进行实时的交互,请求我的 websocket Server,然后我在内部找到对应的 TCP socket 客户端实例进行指令的拼装和发送,接收到回应及数据之后再实时的返回到 J2EE 的页面上。

这里面主要是用到了 nodejs 中的事件发射监听机制 EventEimtter(其实我也不知道搞个事件机制在这到底有用没用),也是怕可能有不同的实现,所以封装了个基本的 Listener 里面用的 event.on()、event.emit() 和 event.removeListener() 这三个基本的,其他的具体以 prototype+call 方式来继承他的操作并加以各自的实现。

哦对,在这过程中也是了解到了 socket.io 的频道的机制,在这里我是用它来广播当前选定的设备所进行的操作,但是它返回的数据只返回给当前控制它的客户端,为此,我还在这上面捣鼓了半天的锁机制,也算是个很简单的实现吧,根据返回数据包中有结束标志的包来释放,核心思想就是不让多人同时操作,但可以看到这台设备在进行什么操作。

我给经理打了个比喻,在一个房间里,有一台电脑(设备),同时只能有一个人在用(反控),其他人必须要等他用完了才能用,这期间就只能看着他用。

差不多现在就是这个程度,我还是不太满意现在的整体实现,可能有下面几个方面:

  1. 如果我需要不单一个端口也就是多个 server,加入其它业务的通信,那么这个怎么设计会将开发成本以及扩展性做到最优。
  2. 目前由于要让一些连接的缓存起来或者配置信息方便使用等,用到了不少全局的变量,然后分布在各个模块,并且各个模块间有一定的耦合性,这种问题要怎么解决。
  3. 再就是考虑到以后可能横向扩展成分布式,前期应该怎么来设计。

这几个问题是我想的比较多而且不是特别擅长的,希望如果有看到想和我交流或者大神有过设计经验的还望不吝赐教。

我的邮箱 yjk99@qq.com