GB28181接入服务器是SkeyeVSS接入GB28181设备/平台的信令交互服务器,GB28181将 SIP定位为联网系统的主要信令基础协议,并利用 SIP协议的有关扩展,实现了对非会话业务的兼顾,例如,对报警业务、历史视音频回放、下载等的支持。目前有GB28181-2011和 GB28181-2016两个版本。
GB28181接入服务器对接入系统的GB28181设备的管理,全部通过一个20位的设备ID号来管理;以SIP协议为载体,以REGISTER、INVITE、MESSAGE等命令实现与28181设备和GB28181流媒体服务器的交互。
随着node.js社区的不断壮大,借助其强大的事件驱动和IO并发能力,已经衍生出了很多很强大的模块(包),实现各种各样的功能,使得服务端程序开发变得非常容易,习惯了 C/C++编程的程序员绝对会感到十分惊讶,因为居然有一种语言开发可以如此高效且简单(PS: 我也就刚学习一个月node.js而已- --!);而本文将要讲解的是一种通过node.js实现接入国标设备以及平台的sip信令服务器的方案。
准备工作
首先,下载node.js并安装,windows,linux平台均支持; 最好有一个比较强大的JS编辑器或者IDE,我推荐一个十分强大且轻量级的IDE兼编辑神器Visual Studio Code。
然后,熟悉npm管理工具的命令,通过npm安装各个需要依赖的node.js模块,其中最重要的sip模块,通过如下命令安装:
npm install sip
node.js拥有强大的包管理工具,可以通过如下命令搜索我们可能需要的node.js模块:
npm search xxx
如下图所示:
其他node.js相关学习大家感兴趣可以在网上找到十分丰富的资料,比如推荐一本比较好书《深入浅出node.js》, 当然最好的建议是:看个毛线的书,老夫都是直接撸代码!
国标接入流程
1 接受下级的注册和注销
首先,我们需要建立一个sip服务来检测和接受下级设备或者平台的注册命令的处理,如下代码所示:
sip.start(option, async request => {
switch (request.method)
{
case common.SIP_REGISTER:
this.emit('register', request);
break;
case common.SIP_MESSAGE:
this.emit('message', request);
break;
case common.SIP_INVITE:
this.emit('invite', request);
break;
case common.SIP_ACK:
this.emit('ack', request);
break;
case common.SIP_BYE:
this.emit('bye', request);
break;
default:
console.log('unsupported: ' + request.method);
break;
}
});
然后,sip服务接收设备端注册请求,回调函数中进行处理:
case common.SIP_REGISTER:
try {
const username = sip.parseUri(request.headers.to.uri).user;
const userinfo = config.userinfos[username];
const session = { realm: config.server.realm };
if (!userinfo)
{
sip.send(digest.challenge(session, sip.makeResponse(request, 401, common.messages[401])));
this.session_.set(username,session);
return;
}
else
{
if(!this.session_.has(username)){
this.session_.set(username,session);
}
userinfo.session = userinfo.session || this.session_.get(username);
if (!digest.authenticateRequest(userinfo.session, request, { user: username, password: userinfo.password }))
{
sip.send(digest.challenge(userinfo.session, sip.makeResponse(request, 401, common.messages[401])));
this.session_.set(username,userinfo.session);
return;
} else
{
this.session_.delete(username);
if(request.headers.expires === '0'){
this.emit('unregister', request);
}
else{
this.emit('register', request);
}