You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在基于ONVIF的C++ GSOAP服务中发送事件通知

ONVIF GSOAP C++服务器事件通知实现方案

核心逻辑说明

ONVIF事件通知采用主动推送模式,无需等待客户端请求,服务器需将事件消息直接发送到客户端订阅时提供的通知端点地址。以下是具体实现步骤:


1. 保存订阅上下文信息

客户端发起订阅(CreateSubscription或PullPointSubscription)时,会携带NotificationConsumer端点地址(HTTP URL),服务器必须持久化该地址及订阅元数据:

#include <unordered_map>
#include <string>
#include <time.h>

struct SubscriptionContext {
    std::string subscriptionId;
    std::string notifyEndpoint; // 客户端通知接收地址
    time_t expires; // 订阅过期时间
};

// 全局容器管理所有有效订阅
std::unordered_map<std::string, SubscriptionContext> g_activeSubscriptions;

2. 构造符合ONVIF规范的事件通知消息

基于event.wsdl生成的gSOAP代码,构造tev__Notify类型的SOAP消息,需包含事件主题、生产者信息、事件内容:

struct soap* createNotifySoap() {
    struct soap* soapHandle = soap_new();
    soap_set_version(soapHandle, SOAP_1_2); // 强制使用SOAP 1.2版本
    return soapHandle;
}

_tev__Notify* buildMotionDetectionEvent(struct soap* soapHandle) {
    _tev__Notify* notifyReq = soap_new__tev__Notify(soapHandle, -1);
    notifyReq->NotificationMessage = soap_new__wsnt__NotificationMessageHolderType(soapHandle, -1);

    // 设置事件主题(按ONVIF规范填写具体事件类型)
    notifyReq->NotificationMessage->Topic = soap_new__wsnt__TopicExpressionType(soapHandle);
    notifyReq->NotificationMessage->Topic->Dialect = "http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet";
    notifyReq->NotificationMessage->Topic->__item = "tns1:VideoAnalytics/MotionDetection";

    // 设置事件生产者(服务器自身地址)
    notifyReq->NotificationMessage->ProducerReference = soap_new_wsa_EndpointReferenceType(soapHandle);
    notifyReq->NotificationMessage->ProducerReference->Address = "http://your-server-ip:8080/onvif/event";

    // 填充事件具体内容
    notifyReq->NotificationMessage->Message = soap_new__tt__MessageType(soapHandle);
    _tt__SimpleItem* eventData = soap_new__tt__SimpleItem(soapHandle);
    eventData->Name = "MotionDetected";
    eventData->Value = "true";
    notifyReq->NotificationMessage->Message->Data = eventData;

    return notifyReq;
}

3. 主动推送消息到客户端端点

使用gSOAP的调用函数,将构造好的消息发送到客户端的通知地址:

void sendEventNotification(const std::string& subscriptionId) {
    auto it = g_activeSubscriptions.find(subscriptionId);
    if (it == g_activeSubscriptions.end()) return;

    struct soap* soapHandle = createNotifySoap();
    _tev__Notify* notifyReq = buildMotionDetectionEvent(soapHandle);

    // 设置SOAP目标端点
    soap_endpoint(soapHandle, it->second.notifyEndpoint.c_str());

    // 发送通知
    int ret = soap_call___tev__Notify(soapHandle, NULL, NULL, notifyReq);
    if (ret != SOAP_OK) {
        soap_print_fault(soapHandle, stderr);
        g_activeSubscriptions.erase(subscriptionId); // 移除无效订阅
    }

    // 释放资源
    soap_destroy(soapHandle);
    soap_end(soapHandle);
    soap_free(soapHandle);
}

4. 订阅生命周期管理

  • 定期遍历g_activeSubscriptions,清理过期的订阅记录
  • 若客户端要求心跳,需定时发送空的Notify消息维持订阅有效性

关键注意事项

  • 严格遵循ONVIF WS-Notification规范,消息命名空间、字段格式必须与event.wsdl定义一致
  • 确保服务器能访问客户端的通知端点,若客户端在NAT环境下,建议优先使用PullPoint模式(客户端主动拉取事件)
  • 测试可使用ONVIF Device Manager工具验证通知接收情况

内容的提问来源于stack exchange,提问作者Александр

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:42:42