当前访客身份:游客 [ 登录  | 注册加入尚学堂]
启用新域名sxt.cn
新闻资讯

使用Node.js实现数据推送

helloworld 发表于 2年前  | 评论(0 )| 阅读次数(1032 )|   0 人收藏此文章,   我要收藏

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

后端推送数据的解决方案有很多,比如轮询、Comet、WebSocket。

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

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

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:


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



客户端JavaScript代码:

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



Node.js服务器代码:

 
var http = require('http'),
    app = http.createServer().listen('8181'),
    io = require('socket.io').listen(app);
io.sockets.on('connection', function (socketIO) {
    // 从客户端接收数据
    socketIO.on('fromWebClient', function (webClientData) {
        // do sth.
    });
    // 客户端断开连接
    socketIO.on('disconnect', function () {
        console.log('DISCONNECTED FROM CLIENT');
    });        
    // 向客户端发送数据
    socketIO.emit('pushToWebClient', jsonData);    
});



建立好客户端同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服务器代码:

 
var http = require('http'),
    net = require('net'),
    app = http.createServer().listen('8181'),
    io = require('socket.io').listen(app),
    nodeServer = new net.Socket();
// 连接到Tomcat
nodeServer.connect(8007, '127.0.0.1', function() {
    console.log('CONNECTED');
});
// 存储客户端的WebSocket连接实例
var aSocket = {};
// 同客户端建立连接
io.sockets.on('connection', function (socketIO) {
    // 从客户端接收数据,然后发送至Tomcat
    socketIO.on('fromWebClient', function (webClientData) {        
        // 存储至映射表
        aSocket[socketIO.id] = socketIO;
        // 发送至Tomcat的数据中添加socket_id
        webClientData['sid'] = socketIO.id;        
        // 发送String类型的数据至Tomcat
        nodeServer.write(JSON.stringify(webClientData));        
    });
    // 客户端断开连接
    socketIO.on('disconnect', function () {
        console.log('DISCONNECTED FROM CLIENT');
    });    
});

// 从Tomcat接收数据
nodeServer.on('data', function (data) {  
    var jsonData = JSON.parse(data.toString());    
    // 分发数据至客户端
    for (var i in jsonData.list) {
        aSocket[jsonData.list[i]['sid']].emit('pushToWebClient', jsonData.list[i].data);
    }
});



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

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

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

分享到:0
关注微信,跟着我们扩展技术视野。每天推送IT新技术文章,每周聚焦一门新技术。微信二维码如下:
微信公众账号:尚学堂(微信号:bjsxt-java)
声明:博客文章版权属于原创作者,受法律保护。如果侵犯了您的权利,请联系管理员,我们将及时删除!
(邮箱:webmaster#sxt.cn(#换为@))
北京总部地址:北京市海淀区西三旗桥东建材城西路85号神州科技园B座三层尚学堂 咨询电话:400-009-1906 010-56233821
Copyright 2007-2015 北京尚学堂科技有限公司 京ICP备13018289号-1 京公网安备11010802015183