使用Node.js实现数据推送

业务场景:后端更新数据推送到客户端(Java部分使用Tomcat服务器)。前端

后端推送数据的解决方案有不少,好比轮询、Comet、WebSocket。node

1. 轮询对于后端来讲开发成本最低,就是按照传统的方式处理Ajax请求并返回数据,在学校的时候实验室的项目一直都采用轮询,由于它最保险也最容易实现。但轮询带来的通讯资源的浪费是没法忽视的,不管数据是否改变,都照常发送请求并响应,并且每次HTTP请求都带有很长的头部信息。web

2. Comet的概念是长链接,客户端发送请求后,后端将链接保持下来,直到链接超时或后端返回数据时再从新创建链接,有效的将通讯资源转移到了服务器上,实际消耗的是服务器资源。json

3. WebSocket是HTML5提供的一种全双工通讯技术,经过“握手”实现客户端与服务器之间的通讯,实时性好,携带的头部也较小,目前支持的浏览器以下:后端

理想的状况是采起WebSocket与Comet结合的方式,对IE8等浏览器采起Comet方式,作降级处理。可是这样一来,后端须要实现两种处理请求的逻辑,即WebSocket与Comet。因此,本文加入Node.js,之因此这样作,是将处理WebSocket(或Comet)的逻辑转移到Node.js部分,不给后端“添麻烦”,由于在实际状况下,前端开发人员推进后端开发人员并不容易。Node.js做为浏览器与Java业务逻辑层通讯的中间层,链接客户端与Tomcat,经过Socket与Tomcat进行通讯(是Socket,不是WebSocket,后端须要实现Socket接口。浏览器

在客户端,WebSocket与Comet经过Socket.io实现,Socket.io会针对不一样的浏览器版本或者不一样客户端选择合适的实现方式(WebSocket, long pull..),Socket.io的引入让处理WebSocket(或长链接)变的很容易。Socket.io缓存

客户端引入socket.io:服务器

1 <script src="static/js/socket.io.js"></script>

客户端JavaScript代码:session

1 var socket = io.connect('127.0.0.1:8181');
2 // 发送数据至服务器
3 socket.emit('fromWebClient', jsonData);
4 // 从服务器接收数据
5 socket.on('pushToWebClient', function (data) {
6     // do sth.
7 });

Node.js服务器代码:app

 1 var http = require('http'),
 2     app = http.createServer().listen('8181'),
 3     io = require('socket.io').listen(app);
 4 io.sockets.on('connection', function (socketIO) {
 5     // 从客户端接收数据
 6     socketIO.on('fromWebClient', function (webClientData) {
 7         // do sth.
 8     });
 9     // 客户端断开链接
10     socketIO.on('disconnect', function () {
11         console.log('DISCONNECTED FROM CLIENT');
12     });        
13     // 向客户端发送数据
14     socketIO.emit('pushToWebClient', jsonData);    
15 });

创建好客户端同Node.js服务器的链接只是第一步,下面还须要创建Node.js服务器与Java业务逻辑层的联系。这时,Node.js服务器则做为客户端,向Tomcat发送TCP链接请求。链接成功后,Node.js服务器和Tomcat创建了一条全双工的通道,并且是惟一的一条,不论有多少个客户端请求,都从Node.js服务器转发至Tomcat;一样,Tomcat推送过来的数据,也经由Node.js服务器分发至各个客户端。

这里存在一个问题,就是在WebSocket链接与Socket链接都创建好以后,两次链接彼此之间是屏蔽的。Tomcat不知道是哪次WebSocket链接发送过来的数据,也不知道是哪一个客户端发来的数据。固然,Node.js能够利用session id发送至Tomcat来标识是哪个客户端,但本文采用的是另一种办法。

客户端同Node.js创建WebSocket链接时,每一个链接都会包含一个实例,这里称它为socketIO。每一个socketIO都有一个id属性用来惟一标识这个链接,这里称它为socket_id。利用socket_id,在Node.js服务器创建一个映射表,存储每个socketIO与socket_id的映射关系。Node.js服务器发送数据给Tomcat时带上这个socket_id,再由Java部分进行一系列处理之后封装好每一个客户端须要的不一样数据一并返回,返回的数据里要有与socket_id的对应关系。这样,Node.js服务器收到Tomcat发来的数据时,经过前面提到的映射表由不一样的socketIO分发至不一样的客户端。

Node.js服务器代码:

 1 var http = require('http'),
 2     net = require('net'),
 3     app = http.createServer().listen('8181'),
 4     io = require('socket.io').listen(app),
 5     nodeServer = new net.Socket();
 6 // 链接到Tomcat
 7 nodeServer.connect(8007, '127.0.0.1', function() {
 8     console.log('CONNECTED');
 9 });
10 // 存储客户端的WebSocket链接实例
11 var aSocket = {};
12 // 同客户端创建链接
13 io.sockets.on('connection', function (socketIO) {
14     // 从客户端接收数据,而后发送至Tomcat
15     socketIO.on('fromWebClient', function (webClientData) {        
16         // 存储至映射表
17         aSocket[socketIO.id] = socketIO;
18         // 发送至Tomcat的数据中添加socket_id
19         webClientData['sid'] = socketIO.id;        
20         // 发送String类型的数据至Tomcat
21         nodeServer.write(JSON.stringify(webClientData));        
22     });
23     // 客户端断开链接
24     socketIO.on('disconnect', function () {
25         console.log('DISCONNECTED FROM CLIENT');
26     });    
27 });
28 
29 // 从Tomcat接收数据
30 nodeServer.on('data', function (data) {  
31     var jsonData = JSON.parse(data.toString());    
32     // 分发数据至客户端
33     for (var i in jsonData.list) {
34         aSocket[jsonData.list[i]['sid']].emit('pushToWebClient', jsonData.list[i].data);
35     }
36 });

上面的代码省略了一些逻辑,好比Node.js服务器从Tomcat接收的数据分为两种,一种是推送过来的数据,另一种是响应请求的数据,这里统一处理推送过来的数据。

在处理通讯时,Node.js发送至Tomcat的数据是String格式,而从Tomcat接收的数据为Buffer对象(8进制),须要转化为String以后再转化为json发送至客户端。

本文只是给出一个这样两次链接的简单例子,具体的业务中须要加入许多东西。既然在项目中引入了Node.js,就须要前端承担更多的事情,好比对数据的处理、缓存、甚至加入不少业务逻辑。

相关文章
相关标签/搜索