物联网时代——Node.js 能做些什么
物联网(Internet of things):顾名思义,所有的物体都能够联网。
那么怎么建立一个这样的通信网络呢?我们今天以搭建提供tcp实时通信服务的服务器为例子。
有人感觉到物联网很神秘,也有人感觉到tcp很陌生,提到http大家可能都很熟悉,其实http就是建立在tcp基础上的一层协议,今天跟着本节课的教程,大家甚至可以自己创建属于自己的通信协议。
开发准备
[x] vscode or sublime 码农的武器
[x] Node.js 基础知识
[x] es6 相关语法
[x] 善学、勤思的良好品质
搭建一个最基础的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服务器搭建。
我们写一个简单的客户端来验证一下
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) })
我们运行下服务端和客户端的代码,发现服务端收到了客户端发来的数据
from client> <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
或许很多人都对这种格式的数据很陌生,其实这是一最基础的底层数据表达方式,即字节流,又称字节数组。
上述的每一个字节都可以通过查询ascii码表来解释,转换成字符串就是
hello world
说了这么多难道就是为了让我们搞个
hello world
?说好的自定义协议呢?
okok!I 服了 U!在设计自定义协议之前,我需要缺人你们是否了解 大端和小端的概念!楼主不是在讲天书!
在计算机系统中,大家都知道有
int8
,int16
,int32
等等这些数字不同形式,但是在计算机中是怎么表示这些数字的,大家清楚吗?如果不清楚的话,请跟我来。大端?小端?不再神秘!
所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
纸上得来终觉浅,绝知此事要躬行!我们来写几个例子!我们直接用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) })
别偷懒,跟着我撸撸代码,你将会提升更多。
- 点赞
- 收藏
- 关注作者
评论(0)