如何在基于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,提问作者Александр
相关产品推荐
相关产品推荐

