物联网时代——Node.js 能做些什么
【摘要】 有人感觉到物联网很神秘,也有人感觉到tcp很陌生,提到http大家可能都很熟悉,其实http就是建立在tcp基础上的一层协议,今天跟着本节课的教程,大家甚至可以自己创建属于自己的通信协议。
物联网(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)
})
别偷懒,跟着我撸撸代码,你将会提升更多。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)