惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
O
OpenAI News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
Webroot Blog
Webroot Blog
GbyAI
GbyAI
S
SegmentFault 最新的问题
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 【当耐特】
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
S
Security Affairs
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
Spread Privacy
Spread Privacy
T
Threatpost
Forbes - Security
Forbes - Security
C
Cisco Blogs
Scott Helme
Scott Helme
Attack and Defense Labs
Attack and Defense Labs
Simon Willison's Weblog
Simon Willison's Weblog
腾讯CDC
The Last Watchdog
The Last Watchdog
Cloudbric
Cloudbric
Last Week in AI
Last Week in AI
Recorded Future
Recorded Future
小众软件
小众软件
V
Vulnerabilities – Threatpost
美团技术团队
人人都是产品经理
人人都是产品经理
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News - Newest:
Hacker News - Newest: "LLM"
I
Intezer
月光博客
月光博客
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园 - 司徒正美
C
Cybersecurity and Infrastructure Security Agency CISA
Martin Fowler
Martin Fowler
博客园 - 聂微东

博客园 - 海滨code

别让AI再从零写一堆优美的屎山了 Hermes Agent 一周暴涨五万 Star,但我劝你别急着追 受够了Vibe Coding的失控?换个起点,让AI事半功倍 写了10年代码的人,在AI编程时代反而最值钱 我让 Claude 和 Codex 同时审计 26 个模块,它们只在 10 个上达成共识 把近5万个源文件喂给AI之前,我先做了一件事 浏览器自动化六大技术路线深度对比:从模拟点击到 Chrome 扩展注入 在 Windows+WSL2 上部署 OpenClaw AI员工的实践与踩坑 为什么 90% 的 AI 开发项目都死在了“提示词工程”的幻觉里? 一文讲清楚OpenClaw是什么,以及Windows下的部署 国内AI编程IDE对比(三)Skill生成能力测试 Codex 5.3 与 Opus 4.6 同日升级,AI Agent今年要爆发了 Google正式上线Gemini In Chrome,国内环境怎样开启。 国内四大AI编程IDE对比(二):从零构建桌面应用实测(补上Trae,幸亏补上了) 国内AI编程IDE对比(二):从零构建桌面应用实测 社交的“诺曼底登陆”:深度解析腾讯元宝“元宝派”的技术逻辑与场景重构 国内四大AI编程IDE对比(一):直观印象与模型能力 【终极踩坑指南】Windows 10上MsQuic证书加载失败?坑不在证书,而在Schannel! 国标GB28181协议客户端开发(四)实时视频数据传输 国标GB28181协议客户端开发(三)查询和实时视频画面
国标GB28181协议客户端开发(二)程序架构和注册
海滨code · 2023-06-25 · via 博客园 - 海滨code

国标GB28181协议客户端开发(二)程序架构和注册

本系列文章旨在探讨国标GB28181协议设备端的开发过程。本文将聚焦于架构设计和设备注册,并详细介绍了设备端的程序架构设计、exosip库介绍和接口分类,以及GB28181设备端的注册流程和信令交互报文。通过阅读本文,读者将深入了解GB28181协议设备端的架构设计原则、exosip库的使用方法,以及设备的注册过程和信令交互的关键报文。

一、程序架构设计

在GB28181协议设备端的开发中,良好的程序架构设计是保证系统稳定性和可扩展性的基础。我们可以考虑以下方面:

  1. 分层架构:将设备端的功能划分为不同的层次,如媒体层、控制层、存储层和网络层等,以实现模块化的开发和维护。

  2. 模块设计:根据功能需求,将设备端划分为不同的模块,如平台接入模块、媒体解析模块、编码模块、解码模块等。每个模块负责特定的功能,通过接口进行交互和通信。

  3. 数据结构设计:GB28181协议涉及到丰富的数据结构,如设备信息、媒体流、信令消息等。在设计数据结构时,需要考虑数据的组织和访问效率,以及与协议规范的兼容性。

以下为开发GB28181协议设备端的程序框架:

二、exosip库介绍和接口分类

eXosip是一个基于oSIP库的扩展库,用于实现SIP协议的开发。它提供了一个事件驱动的编程接口,用于处理SIP信令和实现SIP应用程序,广泛用于GB28181设备端的开发。它提供了丰富的接口和功能,可以简化开发过程。下面是eXosip的内部架构的概述:

  1. SIP上下文(SIP Context):
    eXosip库使用SIP上下文来管理和处理SIP会话。每个SIP上下文都有一个唯一的ID,可以通过函数eXosip_malloc()创建上下文。应用程序可以创建多个上下文来处理不同的SIP会话。

  2. 事件循环(Event Loop):
    eXosip库通过事件循环机制处理接收到的SIP消息和事件。事件循环会持续监听网络套接字,等待SIP消息的到达或定时器事件的触发。当有事件发生时,eXosip库将生成相应的事件,并将其放入事件队列中等待处理。

  3. 事件处理器(Event Handler):
    eXosip库提供了一组事件处理器函数,用于处理各种类型的事件,如注册、呼叫邀请、消息收发等。应用程序可以根据需要注册相应的事件处理器函数,并在事件发生时执行自定义的逻辑。

  4. SIP消息处理器(SIP Message Handler):
    eXosip库提供了一组函数来处理SIP消息,包括解析和构建SIP请求和响应。它使用oSIP库的底层功能来处理SIP消息的解析和组装,并提供了更高级别的接口供应用程序使用。

  5. 网络通信:
    eXosip库使用底层的网络套接字进行SIP通信。它提供了与网络层交互的功能,如创建和绑定套接字、发送和接收SIP消息等。应用程序可以根据需要配置和管理网络通信相关的参数。

eXosip库的内部架构充分利用了oSIP库提供的底层功能,并提供了更高级别的接口和事件驱动的编程模型,使开发者能够更方便地实现基于SIP的应用程序。

exosip库的接口可以分为以下几类:

  1. 初始化和配置接口:包括库的初始化、设置SIP协议栈的参数、配置监听端口等。

  2. 注册和注销接口:用于设备的注册和注销操作,包括注册请求的发送和接收处理等。

  3. 信令交互接口:用于发送和接收SIP信令消息,如呼叫邀请、媒体流控制等。

三、exosip初始化和消息循环

在使用exosip库前,需要进行初始化和配置的操作。具体步骤如下:

  1. 初始化exosip库:调用初始化接口,初始化exosip库,并设置一些全局参数。

  2. 配置SIP协议栈:通过配置接口,设置SIP协议栈的相关参数,如IP地址、端口等。

  3. 创建SIP上下文:使用上下文接口,创建一个SIP上下文,用于后续的注册和信令交互操作。

#include <osip2/osip.h>
#include <eXosip2/eXosip.h>


// 初始化eXosip和osip栈
exosip_ = eXosip_malloc();
ret_code = eXosip_init(exosip_);
if (ret_code != OSIP_SUCCESS)
{
   SIMPLE_LOG("Can't initialize eXosip!");
   exit(1);
}

// 配置exosip库参数,如IP地址和端口
ret_code = eXosip_listen_addr(exosip_, IPPROTO_UDP, NULL, cfg_.sip_local_port, AF_INET, 0);
if (ret_code != OSIP_SUCCESS)
{
   SIMPLE_LOG("eXosip_listen_addr error!");

   eXosip_quit(exosip_);

   exit(1);
}

eXosip_set_user_agent(exosip_, "HbsGBSIP-1.0");

// 发送初始注册报文
SipSendRegister(false, nullptr);

// 接收和处理SIP报文
while (!is_need_stop_)
{
   // 处理事件
   eXosip_event_t* sip_event = eXosip_event_wait(exosip_, 0, 10);

   // 一般处理401/407采用库默认处理
   eXosip_lock(exosip_);
   eXosip_default_action(exosip_, sip_event);
   eXosip_unlock(exosip_);

   // 超时
   if (sip_event == NULL)
   {
      continue;
   }

   // 尝试解析报文头部信息
   OSipMsgParser msg_parser;
   if (sip_event->request)
   {
      msg_parser.ParseHeader(sip_event->request);
   }

   switch (sip_event->type)
   {
      case EXOSIP_REGISTRATION_SUCCESS: {
         // 注册成功处理
         break;
      }
      case EXOSIP_REGISTRATION_FAILURE: {
         // 注册失败处理
         break;
      }
      case EXOSIP_MESSAGE_NEW: {
         // 收到新的SIP消息处理
         if (sip_event->request) {
            // 处理请求消息
            osip_message_t* request = sip_event->request;
            // 解析和处理请求消息
         } else if (sip_event->response) {
            // 处理响应消息
            osip_message_t* response = sip_event->response;
            // 解析和处理响应消息
         }
         break;
      }
      case EXOSIP_CALL_INVITE: {
         // 收到呼叫邀请处理
         // 解析和处理呼叫邀请消息
         break;
      }
      // 其他事件处理...

      default:
         break;
      }

   // 释放事件
   eXosip_event_free(sip_event);
}


// 清理exosip库资源
eXosip_quit(exosip_);
osip_free(exosip_);
exosip_ = NULL;

四、GB28181注册过程中的信令交互报文

注册流程描述如下:

  1. SIP代理向SIP服务器发送 Register请求;

  2. SIP服务器向 SIP代理发送响应401,并在响应的消息头 WWW_Authenticate字段中给出
    适合SIP代理的认证体制和参数;

  3. SIP代理重新向SIP服务器发送 Register请求,在请求的 Authorization字段给出信任书,
    包含认证信息;

  4. SIP 服务器对请求进行验证,如果检查出 SIP 代理身份合法,向 SIP 代理发送成功响应
    200OK,如果身份不合法则发送拒绝服务应答。

WireShark截包后可见:

  1. 第一次注册:
REGISTER sip:34020000002000000001@192.168.1.54:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.54:10561;rport;branch=z9hG4bK639602844
From: <sip:34020000001110000002@192.168.1.54:10561>;tag=91827836
To: <sip:34020000001110000002@192.168.1.54:10561>
Call-ID: 2847584547
CSeq: 1 REGISTER
Contact: <sip:34020000001110000002@192.168.1.54:10561;line=00c3a618be4c249>
Max-Forwards: 70
User-Agent: HbsGBSIP-1.0
Expires: 3600
Content-Length: 0
  1. GB28181平台返回401错误:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.1.54:10561;rport;branch=z9hG4bK639602844
From: <sip:34020000001110000002@192.168.1.54:10561>;tag=91827836
To: <sip:34020000001110000002@192.168.1.54:10561>;tag=1724123124
Call-ID: 2847584547
CSeq: 1 REGISTER
WWW-Authenticate: Digest realm="34020000", nonce="awer23sdfj123123", opaque="c3a02f1ecb122d255c4ae2266129d044", algorithm=MD5
User-Agent: General
Content-Length: 0
  1. 加上鉴权信息后第二次发送注册报文:
REGISTER sip:34020000002000000001@192.168.1.54:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.54:10561;rport;branch=z9hG4bK2311457380
From: <sip:34020000001110000002@192.168.1.54:10561>;tag=91827836
To: <sip:34020000001110000002@192.168.1.54:10561>
Call-ID: 2847584547
CSeq: 0 REGISTER
Contact: <sip:34020000001110000002@192.168.1.54:10561;line=00c3a618be4c249>
Authorization: Digest username="34020000001110000002", realm="34020000", nonce="awer23sdfj123123", uri="sip:34020000002000000001@192.168.1.54:5060", response="dc953f5c48a92517ff6542ef6cd97e20", algorithm=MD5, opaque="c3a02f1ecb122d255c4ae2266129d044"
Max-Forwards: 70
User-Agent: HbsGBSIP-1.0
Expires: 3600
Content-Length: 0
  1. GB28181平台返回200注册成功:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.54:10561;rport;branch=z9hG4bK2311457380
From: <sip:34020000001110000002@192.168.1.54:10561>;tag=91827836
To: <sip:34020000001110000002@192.168.1.54:10561>;tag=31243r3412
Call-ID: 2847584547
CSeq: 0 REGISTER
User-Agent: General
Date: 2023-03-15T16:18:33
Expires: 300
Content-Length: 0

调用eXosip进行注册的代码如下:

osip_message_t* reg = nullptr;

SIMPLE_LOG("new build register\n");

std::string from_str = MakeSIPFromToStr(cfg_.sip_local_device_id,
   cfg_.sip_local_ip, cfg_.sip_local_port);
std::string to_str = MakeSIPFromToStr(cfg_.sip_server_id,
      cfg_.sip_server_ip, cfg_.sip_server_port);

register_id_ = eXosip_register_build_initial_register(exosip_,
   from_str.c_str(),   //"sip:34010000002000000001@127.0.0.1:7777",
   to_str.c_str(),     //"sip:34020000002000000001@127.0.0.1:5060",
   NULL, expire_val, &reg);

auto ret = eXosip_register_send_register(exosip_, register_id_, reg);

合作请加WX:hbstream或企鹅:229375788。(转载请注明作者和出处)

合作请加作者hbstream(http://haibindev.cnblogs.com),转载请注明作者和出处