如何在snap中利用socket.io及websocket来进行实时数据更新

Socket.io可以使得我们的服务器和客户端进行双向的实时的数据交流。它比HTTP来说更具有传输数据量少的优点。同样地,websocket也具有同样的优点。你可以轻松地把你的数据发送到服务器,并收到以事件为驱动的响应,而不用去查询。在今天的教程中,我们来讲一下如何利用socket.io和websocket来做一个双向的通讯。


1)创建一个socket.io的服务器


首先我们先看一下我完成的一个项目:


我们首先看一下我们的snapcraft.yaml文件:

snapcraft.yaml

name: socketio
version: "0.1"
summary: A simple shows how to make use of socket io
description: socket.io snap example

grade: stable
confinement: strict

apps:
  socket:
    command: bin/socketio
    daemon: simple
    plugs: [network-bind]

parts:
  nod:
    plugin: nodejs
    source: .
   

这是一个nodejs的项目。我们使用了nodejs的plugin。我们的package.json文件如下:

package.json

{
  "name": "socketio",
  "version": "0.0.1",
  "description": "Intended as a nodejs app in a snap",
  "license": "GPL-3.0",
  "author": "xiaoguo, liu",
  "private": true,
  "bin": "./app.js",
  "dependencies": {
    "express": "^4.10.2",
    "nodejs-websocket": "^1.7.1",
    "socket.io": "^1.3.7"
  }
}

由于我们需要使用到webserver,所有我们安装了express架构包。另外,我们使用到socket.io及websocket,所有,我们把这些包都打入到我们的snap包中。

再来看看我们的应用app.js的设计:

app.js

#!/usr/bin/env node

var express = require('express');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);	

app.get('/', function(req, res){
   res.sendFile(__dirname + '/www/index.html');
});

app.use(express.static(__dirname + '/www'));

//Whenever someone connects this gets executed
io.on('connection', function(socket){
  console.log('A user connected');
  
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  io.emit('light-sensor-value', '' + value);
	  // console.log("value: " + value)
	  
	  // This is another way to send data
	  socket.send(value);
  }, 2000); 

  //Whenever someone disconnects this piece of code executed
  socket.on('disconnect', function () {
    console.log('A user disconnected');
  });

});

http.listen(4000, function(){
  console.log('listening on *:4000');
});

var ws = require("nodejs-websocket")

console.log("Going to create the server")

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};
 
// Scream server example: "hi" -> "HI!!!" 
var server = ws.createServer(function (conn) {
	
    console.log("New connection")
	var connected = true;
    
    conn.on("text", function (str) {
        console.log("Received "+str)
        conn.sendText(str.toUpperCase()+"!!!")
    })
    
    conn.on("close", function (code, reason) {
        console.log("Connection closed")
        connected = false
    })
        	
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  var data = '{"data":"{0}"}'.format(value)
	  if (connected){
		conn.send(data);
	  }
  }, 2000); 	
}).listen(4001)

在代码的第一部分,我们创建了一个webserver,它使用的端口地址是4000。我们也同时启动了socket.io服务器,等待客户端的连接。一旦有一个连接的话,我们使用如下的代码每过一段时间来发送一些数据:

//Whenever someone connects this gets executed
io.on('connection', function(socket){
  console.log('A user connected');
  
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  io.emit('light-sensor-value', '' + value);
	  // console.log("value: " + value)
	  
	  // This is another way to send data
	  socket.send(value);
  }, 2000); 

  //Whenever someone disconnects this piece of code executed
  socket.on('disconnect', function () {
    console.log('A user disconnected');
  });

});

虽然这些数据是一些随机的,但是我们主要用来展示它是如何工作的。在实际的应用中,这些数据可以是从一些传感器中得到的。在我们的客户端中,我们可以打开webserver运行的地址:


我们可以看到数据不断地进来,并在我们的客户端中显示出来。具体的设计请参考在www目录中的index.html文件。


2)创建一个websocket的服务器


在我们的app.js中,我们利用如下的代码来实现一个websocket的服务器。端口地址为4001。

app.js


var ws = require("nodejs-websocket")

console.log("Going to create the server")

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};
 
// Scream server example: "hi" -> "HI!!!" 
var server = ws.createServer(function (conn) {
	
    console.log("New connection")
	var connected = true;
    
    conn.on("text", function (str) {
        console.log("Received "+str)
        conn.sendText(str.toUpperCase()+"!!!")
    })
    
    conn.on("close", function (code, reason) {
        console.log("Connection closed")
        connected = false
    })
        	
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  var data = '{"data":"{0}"}'.format(value)
	  if (connected){
		conn.send(data);
	  }
  }, 2000); 	
}).listen(4001)

同样地,一旦有个连接,我们每隔两秒钟发送一个数据到我们的客户端。为了说明问题方便,我们设计了一个QML的客户端。

Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Pickers 1.3
import Qt.WebSockets 1.0
import QtQuick.Layouts 1.1

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "dialer.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    function interpreteData(data) {
        var json = JSON.parse(data)
        console.log("Websocket data: " + data)

        console.log("value: " + json.data)
        mainHand.value = json.data
    }

    WebSocket {
        id: socket
        url: input.text
        onTextMessageReceived: {
            console.log("something is received!: " + message);
            interpreteData(message)
        }

        onStatusChanged: {
            if (socket.status == WebSocket.Error) {
                console.log("Error: " + socket.errorString)
            } else if (socket.status == WebSocket.Open) {
                // socket.sendTextMessage("Hello World....")
            } else if (socket.status == WebSocket.Closed) {
            }
        }
        active: true
    }

    Page {
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("dialer")
        }

        Item {
            anchors {
                top: pageHeader.bottom
                left: parent.left
                right: parent.right
                bottom: parent.bottom
            }

            Column {
                anchors.fill: parent
                spacing: units.gu(1)
                anchors.topMargin: units.gu(2)

                Dialer {
                    id: dialer
                    size: units.gu(30)
                    minimumValue: 0
                    maximumValue: 1000
                    anchors.horizontalCenter: parent.horizontalCenter

                    DialerHand {
                        id: mainHand
                        onValueChanged: console.log(value)
                    }
                }


                TextField {
                    id: input
                    width: parent.width
                    text: "ws://192.168.1.106:4001"
                }

                Label {
                    id: value
                    text: mainHand.value
                }
            }
        }
    }
}

运行我们的服务器及客户端:



我们可以看到我们数值在不断地变化。这个客户端的代码在: https://github.com/liu-xiao-guo/dialer

在这篇文章中,我们展示了如何利用socket.io及websocket来进行双向的实时的通讯。在很多的物联网的应用中,我们可以充分利用这些通讯协议来更好地设计我们的应用。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值