设备发现的过程:客户端发送报文到239.255.255.250的3702端口(ONVIF协议规定),服务器收到报文后再向客户端返回一个报文,客户端收到这个报文然后解析出Xaddrs,这就完成了一次设备发现。请看下面代码:
// 正在表达式
std::string ippattren = ("\\d+\.\\d+\.\\d+\.\\d+(\:\\d+|\.{5})");
std::string brand = ("\/name\/(\.\*)\\s");
std::string model = ("\/hardware\/(\.\*)\\s");
std::string stType = ("\/type\/(\.\*)\\s");
// 忽略大小写
std::regex_constants::syntax_option_type fl = std::regex_constants::icase;
// 编译正在表达式
std::regex regExpress(ippattren, fl);
std::regex regBrand(brand,fl);
std::regex regModel(model,fl);
std::regex regType(stType,fl);
std::smatch ms;
char *pBuffer;
//UUID 好最后是变化的否则 onvif 组播服务可能只回复一次
std::string guid_string = "uuid:68749E8A-2EDD-49C0-ABF8-45E0733911BF";
wsddProxy discovery;
//获取guid(windows下叫guid,linux下叫uuid),格式为urn:uuid:8-4-4-4-12,由系统随机产生
static char buf[64] = {0};
GUID guid;
if (S_OK == ::CoCreateGuid(&guid))
{
//如果guid生成成功,则将其转为字符串,保存在buf中
_snprintf_s(buf, sizeof(buf)
, "uuid:%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X"
, guid.Data1
, guid.Data2
, guid.Data3
, guid.Data4[0], guid.Data4[1]
, guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]
, guid.Data4[6], guid.Data4[7]
);
guid_string = buf;
}
//超过5秒没有数据就退出
discovery.recv_timeout = 5;
char* wsa_To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
char* wsa_Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
SOAP_ENV__Header header;
soap_default_SOAP_ENV__Header(&discovery,&header);
header.wsa__MessageID = (char *)guid_string.c_str();
header.wsa__To = wsa_To;
header.wsa__Action = wsa_Action;
discovery.header = &header;
//这个就是传递过去的组播的ip地址和对应的端口发送广播信息
//设置所需寻找设备的类型和范围,二者至少设定一个,否则可能收到非ONVIF设备,出现异常
discovery.soap_endpoint = "soap.udp://239.255.255.250:3702";
struct wsdd__ProbeType wsdd__Probe;
//设置所需设备的类型,tdn为命名空间前缀,为wsdd.nsmap文件中
//{"tdn","http://www.onvif.org/ver10/network/wsdl"}的tdn,
//如果不是tdn,而是其它,如ns1,这里也要随之改为ns1
soap_default_wsdd__ProbeType(&discovery, &wsdd__Probe);
wsdd__Probe.Types = "tdn:NetworkVideoTransmitter";
int result = 0, count = 0;
//通过组播发送Probe探针,发送成功返回0,否则返回-1
result = discovery.send_Probe(/*discovery.soap_endpoint, NULL, */&wsdd__Probe);
if(-1 == result)
{
AfxMessageBox(_T("Probe发送失败!"));
return;
}
else
{
struct __wsdd__ProbeMatches wsdd__Probe;
while(1)
{
//接收ProbeMatches,成功返回0,否则返回-1
result = discovery.recv_ProbeMatches(wsdd__Probe);
if(-1 == result){
//AfxMessageBox(_T("Probe接收失败!"));
return;
}
else
{
string stText,strTemp;
IPCDevice ipcinfo;
// 获取IP
pBuffer = wsdd__Probe.wsdd__ProbeMatches->ProbeMatch->XAddrs;
stText = pBuffer;
if (std::regex_search(stText,ms,regExpress))
{
strTemp = *ms.begin();
int n = strTemp.find(':');
if (n != -1)
{
ipcinfo.strIP = strTemp.substr(0,n);
ipcinfo.strPort = strTemp.substr(n + 1,strTemp.length());
n = ipcinfo.strPort.find('/');
if (n != -1)
{
ipcinfo.strPort = ipcinfo.strPort.substr(0,n);
}
}
}
// 获取厂商及型号
if (wsdd__Probe.wsdd__ProbeMatches->ProbeMatch->Scopes == NULL)
{
continue;
}
pBuffer = wsdd__Probe.wsdd__ProbeMatches->ProbeMatch->Scopes->__item;
stText = pBuffer;
if (std::regex_search(stText,ms,regBrand))
{
strTemp = *ms.begin();
ipcinfo.strBrand = strTemp.substr(6,strTemp.find(" ") - 5);
}
if (std::regex_search(stText,ms,regModel))
{
strTemp = *ms.begin();
ipcinfo.strModel = strTemp.substr(10,strTemp.find(" ") - 9);
}
if (std::regex_search(stText,ms,regType))
{
strTemp = *ms.begin();
ipcinfo.strModel = strTemp.substr(10,strTemp.find(" ") - 9);
}
}
}
//清除变量
discovery.destroy();
}
工程下载地址:https://download.csdn.net/download/xijundian04083099/11953198