最近在做一个实验,接收udp信号发送过来的卫星航迹数据,在后台解算出它的航迹数据,然后将航迹数据发送到浏览器前端,将卫星的航迹图在浏览器前端可视化出来。
一、接收udp信号数据,在后台对原始数据解析解算
上图看到的是是一个udp信号发送模拟器,它发送的是卫星的航迹数据,发送端是在本机的6001端口,接收客户端是在本机的6000端口。(即发送器将udp信号数据从6001端口发送到6000端口)
在node.js中,可用“dgram”数据报模块绑定本机的6000端口,接收到发送过来的udp数据。代码如下:
// 创建服务端,6000端口
const dgram = require('dgram');
let server = dgram.createSocket('udp4');
//绑定端口和主机地址
server.bind(6000);
上面三行代码中,第一行引入了“dgram”数据报模块,引入了该模块就能创建一个声明为“server”的对象,然后用“server”的“bind()”方法,绑定6000端口,就为后面接收到udp数据做准备
//有新数据包被接收时,触发
var pp=[]; //定义一个数组,存放一帧数据中四个航迹点的数据
server.on('message', function (msg, rinfo) {
const buf1=msg.slice(0,2); //切分出航迹信息的HEAD
const buf2=msg.slice(2,4); //切分出航迹信息的N
const buf3=msg.slice(4,6); //切分出航迹信息的TYPE
const buf4=msg.slice(6,42); //切分出第一个航迹点的所有数据
const buf5=msg.slice(42,78); //切分出第二个航迹点所有数据
const buf6=msg.slice(78,114); //切分出第三个航迹点所有数据
const buf7=msg.slice(114,150); //切分出第四个航迹点所有数据
//输出各航迹点的数据
var p1=output(buf4); //得到一帧数据中第一个点的数据
var p2=output(buf5); //得到一帧数据中第二个点的数据
var p3=output(buf6); //得到一帧数据中第三个点的数据
var p4=output(buf7); //得到一帧数据中第四个点的数据
var p=[];
p.push(p1,p2,p3,p4); //定义一个数组,存放一帧数据中的四个航迹点数据
pp=p //将数组p里面的数据放到数组pp中,便于后续操作
console.log(pp);
console.log('\n');
// 解析一个航迹点的各种信息
function output(pointBuff){
let pState=pointBuff.readUIntBE(0,2).toString(16); //解析出航迹点的标志位,分为0,1,2
pState=parseInt(pState,16); //将16进制字符串信息转化为10进制数字
let pNum=pointBuff.readUIntBE(2,1).toString(16); //解析出航迹点的批号,分为1,2,3,4
pNum=parseInt(pNum,16);
let pDistance=pointBuff.readUIntBE(4,2).toString(16); //解析出航迹点的距离
pDistance=parseInt(pDistance,16);
let pAngle=pointBuff.readUIntBE(6,2).toString(16); //解析出航迹点的角度
pAngle=parseInt(pAngle,16);
let pV=pointBuff.readUIntBE(8,2).toString(16); //解析出航迹点的航速
pV=parseInt(pV,16);
let pDre=pointBuff.readUIntBE(10,2).toString(16); //解析出航迹点的航向
pDre=parseInt(pDre,16);
let pHeight=pointBuff.readUIntBE(12,2).toString(16); //解析出航迹点的高度
pHeight=parseInt(pHeight,16);
const pRem="##"; //航迹点其他略去信息
//定义一个数组,存放一个航迹点的各种信息
const p=new Array(8);
p[0]=pState;p[1]=pNum;p[2]=pDistance;p[3]=pAngle;p[4]=pV;
p[5]=pDre;p[6]=pHeight;p[7]=pRem;
// console.log("第"+pNum+"个航迹点数据为:")
// console.log(p);
// console.log("\n");
return p;
}
});
上面的代码是“server”对象的on方法,当接收到数据时候,就会触发“message”事件。由于udp发送过来的数据是以Buffer字节流的形式发送的,所以在该事件中,自己根据实验要求写了一个function函数“output”,用来解析接收到的udp数据。
字节流的解析思路和方法在上一篇博客中也有粗略介绍。
这一段代码的最后结果和目的是得到存放解析后航迹点数据的数组pp
二、将解析后的航迹数据发送到浏览器前端
1、后端部分
在node.js中,可以用到H5里面的websocket API,将后端的数据发送到前端。
首先,需要引入外部依赖包模块,才能在node.js中运用websocket。将控制台切换到该node.js文件所在目录,然后输入“npm install nodejs-websocket --save”即可在该node.js文件用运用websocket。
代码如下:
// 引入websocket模块外部依赖包,(npm install nodejs-websocket --save)
var ws=require('nodejs-websocket');
引入了外部模块,就可以相应的对象了,
var wss=ws.createServer(conn =>{
console.log("服务端与客户端正在连接");
conn.on('text',function(data){
console.log("收到的信息"+data); //接收客户端发送的消息
conn.send(pp.toString()); //当接收到客户端消息的时候,向客户端发送航迹点数据(将航迹点数据转化为字符串或者字节流才能发送)
})
conn.on('close',function(){
console.log("closed");
})
conn.on('error',function(){
console.log('error');
})
});
这里的对象名为“wss”,创建wss的时候,也触发一个回调函数,传来的参数是“conn”,conn的“text”事件是当接收到前端发送数据时候触发,在该事件中,利用conn.send()方法将存放航迹点数据的数组pp发送给前端。
运用websocket将数据从后端发送到前端,需要后端和前端都绑定相同的地址和端口,由于现在都是在本机,所以后端和前端都需要绑定相同端口。在本实验中,绑定的是本机3000端口,如下:
wss.listen(3000,function(){
console.log("正在监听3000端口");
})
2、前端部分
在浏览器前端(html文件),也创建websocket,绑定和后端同样的端口,如下:
// 创建websocket连接
const ws= new WebSocket('ws://localhost:3000');
当websocket连接打开时候,向后端发送数据,从而触发上面提到的后端的“text”事件,使得后端可以给前端发送数据。
// websocket连接打开时候触发事件
ws.onopen=function(e){
console.log("服务器连接成功");
//每隔一秒向服务器发送消息,以便后面每隔一秒收到消息
setInterval(function(){
ws.send("hello");
},1000)
}
这样,就可以接收后端发送来的数据了,可以将它在前端打印出来,代码如下:
// 接收服务器的消息
ws.onmessage= function (e) {
var pp=(e.data).split(","); //将接收到的航迹点数据由字符串转为数组
console.log(pp);
};
最后结果如下图,在浏览器控制台打印出了一系列航迹点数据
总结
经过以上步骤,就将航迹点的udp信号数据,在后端完成解析解算,然后发送到前端了。发送到前端后,就可以运用javascript的e-chart库和jquery库将航迹点数据以动态和图表的形式展示在前端了