引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器。但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素。

研究本例主要为后期BI软件,CRM图标系统使用nodejs socket做铺垫.主要实现的是一个分析表图的推送。

socketio.io 代码库以及官网

https://github.com/socketio/socket.io

http://socket.io/

使用redis来实现集群读写 消息 (采用订阅 分发的策略)

https://github.com/socketio/socket.io-redis

在非socket客户行为中发送socket事件(本例在http中调用)

https://github.com/socketio/socket.io-emitter

node_redis

https://github.com/NodeRedis/node_redis

1.安装和基本使用 npm install socketio.io --save

使用因为本人写的例子是Express照搬官网说明,基本代码结构如下

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(){ /* … */ });
server.listen(3000);

  

2.使用websocket初始化一个echart的图片

socket.js 简单封装下socket.io的一些基本功能,socket.io 提供了三种默认的事件(客户端和服务器都有):connect 、message 、disconnect 。当与对方建立连接后自动触发 connect 事件,当收到对方发来的数据后触发 message 事件(通常为 socket.send() 触发),当对方关闭连接后触发 disconnect 事件。

除去自定义事件之外,本例中还定义了一个额外事件init chart data,用来初始化echart图的数据。

服务端推送消息的主要方式

1.socket.emit() :向建立该连接的客户端广播

2.socket.broadcast.emit() :向除去建立该连接的客户端的所有客户端广播

3.io.sockets.emit() :向所有客户端广播,等同于上面两个的和

此处用到了socket.emit()

socket.io-redis 用来集群推送消息,使用出版/订阅的软件模式,io.adapter()是设置消息缓存方式的,默认为内存,但是集群中内存显然是无法共享的,所以使用socket.io-redis用redis作为缓存中心,注意https://github.com/socketio/socket.io-redis是基于node-redis的,socket.io-redis的说明文档很长时间没有更新了,如果redis有密码一类的雁阵,必须使用

io.adapter(adapter({ pubClient: pub, subClient: sub })); 出版订阅的缓存可以用同一个redis服务器,redis可以部署集群,本例就不在这方面说明了。node-redis2.6之后密码验证使用password为密码参数,而不是官网所写的auth_pass

var mockData = [
[10, 52, 200, 334, 390, 330, 220]
]; var ioCreater = function(server) {
var io = require('socket.io')(server);
io.on('connection', function (socket) {
socket.emit('init chart data', {data:mockData[0]}); //socket客户端发送一个消息 init chart data ,内容为一组数据
socket.on('disconnect', function(){ //断开socket连接的时候触发
console.log('user disconnected');
});
socket.on('message', function(){ //接收socket连接消息的时候触发
console.log('received a message');
});
socket.on('connect', function(){ //建立socket连接时候触发
console.log('connect a socket client');
}); });
var redis = require('redis');
var adapter = require('socket.io-redis');
var pub = redis.createClient({host:"192.168.0.13", port:"6379", password: "123456" });
var sub = redis.createClient({host:"192.168.0.13", port:"6379", password: "123456" ,return_buffers: true});
io.adapter(adapter({ pubClient: pub, subClient: sub })); //使用socket.io-adapter设置缓存依赖
return io; 
}
module.exports = ioCreater;

 

app.js express项目主入口,创建8080端口web服务器的时候创建一个socket服务

var socket = require('./socket/socket');

var port = normalizePort(process.env.PORT || '8080');
app.set('port', port);
var server = http.createServer(app);
var io = socket(server);
server.listen(port);

推送入口,一个express的路由charts.js,其中2个路由,

simpleBarChart转跳simpleBarChart页面,因为用了handlebars的模版引擎设置layout:false来不包含layout模版片段。

pollingChartData 为推送socket消息请求路由,使用socket.io-emitter.js 来发送事件,注意socket.io-emitter.js也长时间没有人维护了,修改了其中一段代码来实现支持redis密码验证.

socket.io-emitter.js  59行修改如下

    if (!redis) {
if (!opts.socket && !opts.host) throw new Error('Missing redis `host`');
if (!opts.socket && !opts.port) throw new Error('Missing redis `port`');
redis = opts.socket
? client(opts.socket)
: client(opts);
}

  

使用count基数器计数,每次推送重mockdata中取模得到新的数据,通过emitter redis服务器,推送消息

var express = require('express');
var router = express.Router();
var server = express();
server.use('/charts', router);
var emitter = require('../tools/socket.io-emitter.js'); //此处修改来自socket.io-emitter.js var mockData = [
[10, 52, 200, 334, 390, 330, 220],
[10, 52, 200, 334, 390, 330, 220],
[88, 32, 87, 432, 4, 30, 87],
[42, 52, 87, 23, 390, 42, 87],
[42, 52, 200, 334, 390, 42, 876],
[53, 52, 321, 324, 42, 330, 32],
[44, 87, 4, 32, 390, 42, 32],
[53, 87, 42, 334, 54, 330, 220],
[530, 52, 54, 43, 43, 330, 32],
[88, 13, 233, 98, 43, 44, 32]
]; var count =1; const disableLayout ={layout: false}; // disable interface layout.hbs user config layout: false
router.get('/simpleBarChart', function(req, res, next) {
var result = Object.assign({title: 'chart demo'},disableLayout);
res.render('charts/simpleBarChart',result);
}); router.get('/pollingChartData', function(req, res, next) {
//10.10.10.96:8080
var io = emitter({ host: '192.168.0.13', port: 6379, password: "123456" }); //创建一个emitter事件服务器,
setTimeout(function(){
count++;
io.emit('new chart data', {data:mockData[count%10]}); //推送一条消息
res.render('index', { title: '推送一条消息成功!'});
}, 500); }); module.exports = server;

  

  

前端页面,express引用socket.io后,自动可以通过访问/socket.io/socket.io.js 的前端库,本例中接收了2种socket消息,一种刚进入页面创建socket连接的时候接收的一条init chart data的消息,以及接收通过pollingChartData推送来的new chart data的消息.

<!DOCTYPE html>
<html>
<head>
<!-- 声明文档使用的字符编码 -->
<meta charset='utf-8'>
<!-- 优先使用 IE 最新版本和 Chrome -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<!-- 启用360浏览器的极速模式(webkit) -->
<meta name="renderer" content="webkit">
<!-- 页面描述 -->
<meta name="description" content="chart demo"/>
<!-- 页面关键词 -->
<meta name="keywords" content="chart demo"/>
<!-- 网页作者 -->
<meta name="author" content="name, email@gmail.com"/>
<!-- 搜索引擎抓取 -->
<meta name="robots" content="index,follow"/>
<!-- 为移动设备添加 viewport -->
<meta name="viewport" content="initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no">
<title>chart</title>
<link rel='stylesheet' href='/css/style.css'/>
<link rel='stylesheet' href='/css/charts/charts.css'/>
<script type="text/javascript" src="/js/library/echart/3.3.2/echarts.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script> </head>
<body>
<div class="chart-wrap" id="chart-wrap"></div>
<script type="text/javascript">
var mychart = echarts.init(document.getElementById("chart-wrap"));
var option = {
color: ['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '直接访问',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
}; var drawChart = function(data){
option.series[0].data = data;
mychart.setOption(option);
}; var socket = io("ws://10.10.10.96:8080"); //通过ip和端口建立一个socket client
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('message', function(){
console.log('received a message');
});
socket.on('connect', function(){
console.log('connect a socket client');
});
socket.on('init chart data', function(data){
console.log('init chart data');
drawChart(data.data);
});
socket.on('new chart data', function(data){
console.log('new chart data');
drawChart(data.data);
}); </script>
</body>
</html>

  

最后结果,通过http://localhost:8080/charts/simpleBarChart访问获得一个简单的echart图表,

通过http://localhost:8080/charts/pollingChartData访问推送新数据重绘图表,每次发送一次请求,重新绘制一次图片。

socket.io简单入门(一.实现简单的图表推送)的更多相关文章

  1. 用socket.io实现websocket的一个简单例子

    socket.io 是基于 webSocket 构建的跨浏览器的实时应用. 逛博客发现几个比较好的 一.用socket.io实现websocket的一个简单例子 http://biyeah.iteye ...

  2. Netty实现一个简单聊天系统(点对点及服务端推送)

    Netty是一个基于NIO,异步的,事件驱动的网络通信框架.由于使用Java提供 的NIO包中的API开发网络服务器代码量大,复杂,难保证稳定性.netty这类的网络框架应运而生.通过使用netty框 ...

  3. dwr简单应用及一个反向ajax消息推送

    由于项目中最近需要用到dwr实现一些功能,因此在网上和dwr官网上找了一些资料进行学习.在此记录一下.(此处实现简单的dwr应用和dwr消息反向推送) 一.引入dwr的包 <dependency ...

  4. dotnet core使用IO合并技巧轻松实现千万级消息推送

    之前讲述过多路复用实现单服百万级别RPS吞吐,但在文中有一点是没有说的就是消息IO合并,如果缺少了消息IO合并即使怎样多路复用也很难达到百万级别的请求响毕竟所有应用层面的网络IO读写都是非常损耗性能的 ...

  5. kettle教程(1) 简单入门、kettle简单插入与更新。打开kettle

    本文要点:Kettle的建立数据库连接.使用kettle进行简单的全量对比插入更新:kettle会自动对比用户设置的对比字段,若目标表不存在该字段,则新插入该条记录.若存在,则更新.   Kettle ...

  6. socket.io分布式

    socket.io是目前较为流行的web实时推送框架,其基于nodejs语言开发,底层用engine.io实现. 借助nodejs语言异步的特性,其获得了不错的性能.但单个实例的socket.io依然 ...

  7. CabloyJS V3.2.0支持Socket IO

    CabloyJS v3.2.0引入了Socket IO,并且实现了统一的在线推送和离线推送机制 效果演示 1. IM 用户向系统发送一条消息,系统通过websocket在线通道向用户推送一条回复 2. ...

  8. ECharts.js 超简单入门(本质canvas)

    ECharts.js 超简单入门(本质canvas) 一.总结 一句话总结:echarts这些图标的本质都是canvas. 二.ECharts.js学习(一) 简单入门 EChart.js 简单入门 ...

  9. 基于react+react-router+redux+socket.io+koa开发一个聊天室

    最近练手开发了一个项目,是一个聊天室应用.项目虽不大,但是使用到了react, react-router, redux, socket.io,后端开发使用了koa,算是一个比较综合性的案例,很多概念和 ...

随机推荐

  1. Oracle插入日期格式出现 ORA-01843: not a valid month的解决办法

    Oracle 在插入时间类型的时候如果不注意插入的格式就很容易出错,基本上只要转一下时间格式就可以解决. DateTime转成特定格式的字符串: var dateString = DateTime.N ...

  2. MVC+EF6+Oracle,提示ORA-01918: user '***' does not exist

    1.在上下文里重载OnModelCreating:        //没用到这个方法         protected override void OnModelCreating(DbModelBu ...

  3. 【转】BAT 批处理脚本 教程

    第一章 批处理基础第一节 常用批处理内部命令简介批处理定义:顾名思义,批处理文件是将一系列命令按一定的顺序集合为一个可执行的文本文件,其扩展名为BAT或者CMD.这些命令统称批处理命令.小知识:可以在 ...

  4. [LeetCode] Largest Rectangle in Histogram 直方图中最大的矩形

    Given n non-negative integers representing the histogram's bar height where the width of each bar is ...

  5. 【机器学习Machine Learning】资料大全

    昨天总结了深度学习的资料,今天把机器学习的资料也总结一下(友情提示:有些网站需要"科学上网"^_^) 推荐几本好书: 1.Pattern Recognition and Machi ...

  6. 「post中文参数问题」以及「验证码自动识别备忘」

    前言 之前搞过几次模拟登录,都是模拟 post 后取到 cookie,之后便能用这个 cookie 愉快玩耍.这次碰到了验证码,其实只需手动登录一次,手动取到 cookie 后也能玩耍,不过 cook ...

  7. Intellij IDEA 快捷键

    Ctrl+Shift + Enter,语句完成 "!",否定完成,输入表达式时按 "!"键 Ctrl+E,最近的文件 Ctrl+Shift+E,最近更改的文件 ...

  8. redis分片

    本文是在window环境下测试 什么是分片 当数据量大的时候,把数据分散存入多个数据库中,减少单节点的连接压力,实现海量数据存储 那么当多个请求来取数据时,如何知道数据在哪个redis呢,redis有 ...

  9. vue.js 第三课

    1.构造器 constructor 2.属性和方法 properties methods 3.实例生命周期 instance_lifecycle   1.vue.js都是通过 var vm=new V ...

  10. 自定义UIBarButtonItem

    如果是通过UIButton自定义UIBarButtonItem,那么通过如下这个方式设置title是无效的.必须要直接给button设置title. self.navigationItem.right ...