Node.js实现数据推送


Posted in Javascript onApril 14, 2016

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

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

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

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

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

Node.js实现数据推送

理想的情况是采取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,就需要前端承担更多的事情,比如对数据的处理、缓存、甚至加入很多业务逻辑。

Javascript 相关文章推荐
xtree.js 代码
Mar 13 Javascript
js点击页面其它地方将某个显示的DIV隐藏
Jul 12 Javascript
js实现简单登录功能的实例代码
Nov 09 Javascript
javascript ajax的5种状态介绍
Aug 18 Javascript
使用JS实现jQuery的addClass, removeClass, hasClass函数功能
Oct 31 Javascript
使用PHP+JavaScript将HTML页面转换为图片的实例分享
Apr 18 Javascript
使用JQuery选择HTML遍历函数的方法
Sep 17 Javascript
React + webpack 环境配置的方法步骤
Sep 07 Javascript
Vue 自定义标签的src属性不能使用相对路径的解决
Sep 17 Javascript
使用vue-cli4.0快速搭建一个项目的方法步骤
Dec 04 Javascript
Vue v-for中的 input 或 select的值发生改变时触发事件操作
Aug 31 Javascript
javascript中call,apply,bind的区别详解
Dec 11 Javascript
node.js实现端口转发
Apr 14 #Javascript
即将发布的jQuery 3 有哪些新特性
Apr 14 #Javascript
谈一谈JS消息机制和事件机制的理解
Apr 14 #Javascript
Kindeditor在线文本编辑器如何过滤HTML
Apr 14 #Javascript
基于RequireJS和JQuery的模块化编程日常问题解析
Apr 14 #Javascript
[原创]JQuery 在表单提交之前修改 提交的值
Apr 14 #Javascript
javaScript数组迭代方法详解
Apr 14 #Javascript
You might like
PHP中header和session_start前不能有输出原因分析
2013/01/11 PHP
Docker配置PHP开发环境教程
2016/12/21 PHP
Add Formatted Text to a Word Document
2007/06/15 Javascript
Jquery知识点一 Jquery的ready和Dom的onload的区别
2011/01/15 Javascript
基于mootools 1.3框架下的图片滑动效果代码
2011/04/22 Javascript
js实现倒计时(距离结束还有)示例代码
2013/07/24 Javascript
jquery delay()介绍及使用指南
2014/09/02 Javascript
jquery使用each方法遍历json格式数据实例
2015/05/18 Javascript
JavaScript中的bold()方法使用详解
2015/06/08 Javascript
详解Bootstrap创建表单的三种格式(一)
2016/01/04 Javascript
Markdown与Bootstrap相结合实现图片自适应属性
2016/05/04 Javascript
AngularJS  双向数据绑定详解简单实例
2016/10/20 Javascript
基于百度地图实现产品销售的单位位置查看功能设计与实现
2016/10/21 Javascript
从parcel.js打包出错到选择nvm的全部过程
2018/01/23 Javascript
Angular2.0实现modal对话框的方法示例
2018/02/18 Javascript
详解Angular操作cookies方法
2018/06/01 Javascript
js实现移动端轮播图
2020/12/21 Javascript
微信小程序云开发如何使用npm安装依赖
2019/05/18 Javascript
mock.js模拟数据实现前后端分离
2019/07/24 Javascript
javascript设计模式 ? 外观模式原理与用法实例分析
2020/04/15 Javascript
微信小程序弹窗禁止页面滚动的实现代码
2020/12/30 Javascript
k8s node节点重新加入master集群的实现
2021/02/22 Javascript
python Django模板的使用方法
2016/01/14 Python
你应该知道的python列表去重方法
2017/01/17 Python
python3.x实现发送邮件功能
2018/05/22 Python
pyqt5 使用label控件实时显示时间的实例
2019/06/14 Python
Python 生成VOC格式的标签实例
2020/03/10 Python
html5实现九宫格抽奖可固定抽中某项奖品
2020/06/15 HTML / CSS
丹尼尔惠灵顿手表天猫官方旗舰店:Daniel Wellington
2017/08/25 全球购物
韩国演唱会订票网站:StubHub韩国
2019/01/17 全球购物
德国拖鞋网站:German Slippers
2019/11/08 全球购物
工作证明范本(2篇)
2014/09/14 职场文书
交通事故协议书范本
2014/11/18 职场文书
小学六年级毕业感言
2015/07/30 职场文书
班级管理经验交流材料
2015/11/02 职场文书
python实现商品进销存管理系统
2022/05/30 Python