使用onvif协议栈时,客户端默认不绑定任何ip地址,导致发送的时候使用了127.0.0.1作为本地地址,一般情况下也不会出现问题,但是某些环境下,比如防火墙或者计算机配置,会导致该地址发送的数据无法被设备接收。经过比较测试,当使用 ONVIF Conformance Test 工具,采用IPv4 Discover Device和指定IP测试Discover Device时,发送数据的源地址不同,IPv4使用了 127.0.0.1,设备没有对数据进行回复。这种情况下采用onvif协议栈同样不能得到数据。奇怪的是ONVIF Conformance Test 工具是可以绑定IP的,但是onvif协议栈在soap_send___wsdd__Probe → soap_connect时,只创建了socket连接,没有绑定ip,设置没有绑定ip的接口,只能修改协议栈。
tcp_connect 函数用来创建socket连接,其中有对client接口的预留,但是没有函数可以直接处理:
if (soap->client_port >= 0)
{
struct sockaddr_in addr;
memset((void*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(soap->client_port);
if (bind(sk, (struct sockaddr*)&addr, sizeof(addr)))
{
soap->errnum = soap_socket_errno;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind before connect\n"));
(void)soap_set_receiver_error(soap, tcp_error(soap), "bind failed in tcp_connect()", SOAP_TCP_ERROR);
(void)soap->fclosesocket(soap, sk);
soap->client_port = -1;
return soap->socket = SOAP_INVALID_SOCKET;
}
soap->client_port = -1; /* disable bind before connect, so need to set it again before the next connect */
}
当client_port不小于0时,会进行相关绑定操作,默认初始化会给-1,导致该语句不执行。在程序中添加对addr中IP地址的初始化:addr.sin_addr.s_addr = inet_addr(soap->client_addr);在进行绑定就可以了。协议栈中预留了地址接口,但不知道为何没有使用。
客户端创建了soap后,将client_port置为0,client_addr设置为本地IP即可,若不设置,则按照默认情况配置,不会对协议栈造成影响。