物联网时代——Node.js 能做些什么

举报
王小艺 发表于 2020/09/29 18:01:22 2020/09/29
【摘要】 有人感觉到物联网很神秘,也有人感觉到tcp很陌生,提到http大家可能都很熟悉,其实http就是建立在tcp基础上的一层协议,今天跟着本节课的教程,大家甚至可以自己创建属于自己的通信协议。

物联网(Internet of things):顾名思义,所有的物体都能够联网。

那么怎么建立一个这样的通信网络呢?我们今天以搭建提供tcp实时通信服务的服务器为例子。

有人感觉到物联网很神秘,也有人感觉到tcp很陌生,提到http大家可能都很熟悉,其实http就是建立在tcp基础上的一层协议,今天跟着本节课的教程,大家甚至可以自己创建属于自己的通信协议。

  1. 开发准备

    • [x] vscode or sublime 码农的武器

    • [x] Node.js 基础知识

    • [x] es6 相关语法

    • [x] 善学、勤思的良好品质

  2. 搭建一个最基础的tcp服务器

     import net from 'net'
    
     var server = net.createServer((conn) => {
         conn.on('data', (data) => {
             console.log('from client> ', data)
         })
     })
    
     server.on('error', (err) => {
         console.log(err)
         return process.exit(0)
     })
    
     server.listen(3000)

    10行代码完成了一个最基础的tcp服务器搭建。

  3. 我们写一个简单的客户端来验证一下

     import net from 'net'
    
     var client = net.createConnection({port: 3000}, (err) => {
         if (err) {
             console.log(err)
         } else {
             client.write('hello world')
         }
     })
    
     client.on('data', (data) => {
         console.log('from server> ', data)
     })
  4. 我们运行下服务端和客户端的代码,发现服务端收到了客户端发来的数据

     from client>  <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>

    或许很多人都对这种格式的数据很陌生,其实这是一最基础的底层数据表达方式,即字节流,又称字节数组。

    上述的每一个字节都可以通过查询ascii码表来解释,转换成字符串就是 hello world

  5. 说了这么多难道就是为了让我们搞个 hello world?说好的自定义协议呢?
    okok!I 服了 U!在设计自定义协议之前,我需要缺人你们是否了解 大端和小端的概念!


    楼主不是在讲天书!

    在计算机系统中,大家都知道有int8,int16,int32等等这些数字不同形式,但是在计算机中是怎么表示这些数字的,大家清楚吗?如果不清楚的话,请跟我来。

  6. 大端?小端?不再神秘!

    所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

    所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

    纸上得来终觉浅,绝知此事要躬行!我们来写几个例子!我们直接用Node.js 的repl功能即可,命令行输入 node,进入该模式 (该模式下enter代表一次输入)

     var a = 16
     var b = Buffer.alloc(2) // 给b分配2个字节,表示uint16数字
     var c = Buffer.alloc(2) // 同样给c分配2个字节,表示uint16数字
     b.writeUInt16LE(a)  // 以小端写入 
     c.writeUInt16BE(a)  // 以大端写入

    大家能才到b、c的运行结果分别是什么吗?这里不卖官子。

     b: <buffer 10 00>
     c: <buffer 00 10>

    细心聪明的大家肯定发现了,对照我们刚才讲的大端小端的概念,I think you got it!

自定义协议

这里我提供一个简单的生成crc16校验码程序


```
function crc16 (buffer) {
    var wCRC_Table = [
        0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
        0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
    ]

    var crcWord = 0xFFFF
    var result = Buffer.alloc(2)
    var start = 0
    var length = buffer.length

    function Drv_Crc_Acc(data) {
        var temp

        temp = wCRC_Table[(data ^ crcWord) & 15] ^ (crcWord >> 4)
        crcWord = wCRC_Table[((data >> 4) ^ temp) & 15] ^ (temp >> 4)
    }
    while (start < length) {
        Drv_Crc_Acc(buffer[start]);
        start++
        if (start == length) {
            result.writeUInt16LE(crcWord)
            return result
        }
    }
}
```

3.hi,小伙伴们,一份简单的自定义的协议就是如此简单哟!下面让我们简单的来验证一下吧。

//server.js
import net from 'net'


function crc16 (buffer) {
    var wCRC_Table = [
        0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
        0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
        ]

    var crcWord = 0xFFFF
    var result = Buffer.alloc(2)
    var start = 0
    var length = buffer.length

    function Drv_Crc_Acc(data) {
        var temp

        temp = wCRC_Table[(data ^ crcWord) & 15] ^ (crcWord >> 4)
        crcWord = wCRC_Table[((data >> 4) ^ temp) & 15] ^ (temp >> 4)
    }


    while (start < length) {
        Drv_Crc_Acc(buffer[start]);
        start++
        if (start == length) {
            result.writeUInt16LE(crcWord)
            return result
        }
    }
}

function parser(buffer) {
    let head = buffer.slice(0,2)
    let gps = buffer.slice(2,3)
    let length = buffer.slice(3,4)
    let data_buffer = buffer.slice(4,15)
    let crc = buffer.slice(15)
    let crc_vali = crc16(buffer.slice(0,15))
    if (crc.compare(crc_vali) == 0) {
        console.log('crc校验成功')
        let lat = data_buffer.readInt32LE(0) / 10000000
        let lng = data_buffer.readInt32LE(4) / 10000000
        let sat_no = data_buffer.readUInt8(8)
        let alt = data_buffer.readInt16LE(9) / 10

        console.log(`gps location is lat:${lat},lng:${lng},height:${alt}m,current sat Num: ${sat_no}`)
    }
} 

var server = net.createServer((conn) => {
    conn.on('data', (data) => {
        parser(data)
    })
})


server.on('error', (err) => {
    console.log(err)
    return process.exit(0)
})

server.listen(4000, (e) => {
    console.log(e, `running`)
})
//client.js
import net from 'net'

function crc16 (buffer) {
    var wCRC_Table = [
        0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
        0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
        ]

    var crcWord = 0xFFFF
    var result = Buffer.alloc(2)
    var start = 0
    var length = buffer.length

    function Drv_Crc_Acc(data) {
        var temp

        temp = wCRC_Table[(data ^ crcWord) & 15] ^ (crcWord >> 4)
        crcWord = wCRC_Table[((data >> 4) ^ temp) & 15] ^ (temp >> 4)
    }


    while (start < length) {
        Drv_Crc_Acc(buffer[start]);
        start++
        if (start == length) {
            result.writeUInt16LE(crcWord)
            return result
        }
    }
}

var client = net.createConnection({port: 4000}, () => {
    let head = new Buffer('de1e','hex')  // 固定头
    let gps = new Buffer('01','hex') // gps协议 0x01

    let length = new Buffer('0b','hex') // 数据段长度为11,16进制表示就是 0x0b

    let lat = 32.083  // 模拟纬度
    let lng = 118.32019  // 模拟经度 
    let sat_num = 12 // 模拟搜星数
    let alt = 5.3 // 模拟高度

    let data_buffer = Buffer.alloc(11) //根据gps协议,总共有11个字节的数据段长度
    data_buffer.writeInt32LE(lat * 10000000,0)    
    data_buffer.writeInt32LE(lng * 10000000,4)
    data_buffer.writeUInt8(sat_num,8)
    data_buffer.writeInt16LE(alt * 10, 9)

    let crc = crc16(Buffer.concat([head, gps, length ,data_buffer]))

    let cmd = Buffer.concat([head,gps,length,data_buffer,crc])
    console.log(cmd)
    client.write(cmd)

})

client.on('data', (data) => {
    console.log('from server> ', data)
})

别偷懒,跟着我撸撸代码,你将会提升更多。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。