zoukankan      html  css  js  c++  java
  • socket.io简单入门(一.实现简单的图表推送)

    引子:随着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访问推送新数据重绘图表,每次发送一次请求,重新绘制一次图片。

  • 相关阅读:
    【Oracle】实体化视图
    安装Linux Centos系统硬盘分区方法
    .NET基础一
    【MySQL】无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止
    Linux基础一
    SQL Server中生成100万行8位纯数字的随机数(转)
    SQL Server配置数据库邮件
    SQL点点滴滴_聪明的小写法(持续更新中)
    过去的2017和已经到来的2018
    【Oracle】PL/SQL Developer使用技巧(持续更新中)
  • 原文地址:https://www.cnblogs.com/xiashan17/p/6126527.html
Copyright © 2011-2022 走看看