socket.io簡單入門(一.實現簡單的圖表推送)

引子:隨着nodejs蓬勃發展,雖然主要業務系統由於架構健壯性不會選擇nodejs座位應用服務器。可是大量的內部系統卻可使用nodejs試水,大量的前端開發人員轉入全堆開發也是一個因素。javascript

研究本例主要爲後期BI軟件,CRM圖標系統使用nodejs socket作鋪墊.主要實現的是一個分析表圖的推送。css

 

socketio.io 代碼庫以及官網html

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

http://socket.io/java

使用redis來實現集羣讀寫 消息 (採用訂閱 分發的策略)node

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

在非socket客戶行爲中發送socket事件(本例在http中調用)github

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

node_redisredis

https://github.com/NodeRedis/node_redis

 

 

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

使用由於本人寫的例子是Express照搬官網說明,基本代碼結構以下

1

2

3

4

5

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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設置緩存依賴

1

return io; <br>}<br> module.exports = ioCreater;

 

app.js express項目主入口,建立8080端口web服務器的時候建立一個socket服務

1

2

3

4

5

6

7

8

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服務器,推送消息

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

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的消息.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

<!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訪問推送新數據重繪圖表,每次發送一次請求,從新繪製一次圖片。

相關文章
相關標籤/搜索