基于udp组播,没有用gsoap工具,虚拟机伪装成ipc,onvif device test tool作为客户端。
通过wireshark抓包发现,discover的核心是uuid。服务端返回的数据包中必须返回从客户端接收的uuid。
============================================================================
//groupcast_discover_server.c
#include
#include
#include
#include
#include
#include
//#include
//#include
//#include
#define BUFLEN 4095
int main (int argc, char **argv)
{
char uu_buf[1024]={0};
char *cust_uuid = 0;
struct sockaddr_in groupcast_addr,the_member;
int sockfd;
unsigned char loop;
char recmsg[BUFLEN + 1];
unsigned int socklen, n;
struct ip_mreq mreq;
#if 0
char *msg="\n\
\n\
\n\
uuid:2419d68a-2dd2-21b2-a205-4A69A95DB56D \n\
uuid:251984b5-d773-4d2e-a21d-d248cdd2eebf \n\
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous \n\
http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches \n\
\n\
\n\
\n\
\n\
\n\
urn:uuid:2419d68a-2dd2-21b2-a205-4A69A95DB56D \n\
\n\
\n\
ttl \n\
\n\
tds:Device \n\
onvif://www.onvif.org/type/NetworkVideoTransmitter\r\nonvif://www.onvif.org/name/IPC_2802222\r\nonvif://www.onvif.org/location/Country/China \n\
http://192.168.42.103:5000/onvif/device_service \n\
1 \n\ \n\
\n\
\n\
\n\n";
#endif
char *aa= "\n\
\n\
\n\
uuid:2419d68a-2dd2-21b2-a205-4A69A95DB56D \n\
uuid:";
char *bb = " \n\
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous \n\
http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches \n\
\n\
\n\
\n\
\n\
\n\
urn:uuid:2419d68a-2dd2-21b2-a205-4A69A95DB56D \n\
\n\
\n\
ttl \n\
\n\
tds:Device \n\
onvif://www.onvif.org/type/NetworkVideoTransmitter\r\nonvif://www.onvif.org/name/IPC_2802222\r\nonvif://www.onvif.org/location/Country/China \n\
http://192.168.42.100:5000/onvif/device_service \n\
1 \n\ \n\
\n\
\n\
\n\n";
/* 创建 socket 用于UDP通讯 */
sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
printf ("socket creating err in udptalk\n");
exit (1);
}
/* 设置要加入组播的地址 */
bzero(&mreq, sizeof (struct ip_mreq));
inet_pton(AF_INET,"239.255.255.250",&the_member.sin_addr);
/* 设置组地址 */
bcopy (&the_member.sin_addr.s_addr, &mreq.imr_multiaddr.s_addr, sizeof (struct in_addr));
/* 设置发送组播消息的源主机的地址信息 */
mreq.imr_interface.s_addr = htonl (INADDR_ANY);
/* 把本机加入组播地址,即本机网卡作为组播成员,只有加入组才能收到组播消息 */
//if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP | IP_MULTICAST_LOOP, &mreq,sizeof (struct ip_mreq)) == -1)
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP , &mreq,sizeof (struct ip_mreq)) == -1)
{
perror ("setsockopt");
exit (-1);
}
loop = 0;
if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,sizeof (loop)) == -1)
{
printf("IP_MULTICAST_LOOP set fail!\n");
}
socklen = sizeof (struct sockaddr_in);
memset (&groupcast_addr, 0, socklen);
groupcast_addr.sin_family = AF_INET;
groupcast_addr.sin_port = htons (3702);
inet_pton(AF_INET, "239.255.255.250", &groupcast_addr.sin_addr);
/* 绑定自己的端口和IP信息到socket上 */
if (bind(sockfd, (struct sockaddr *) &groupcast_addr,sizeof (struct sockaddr_in)) == -1)
{
printf ("Bind error\n");
exit (0);
}
while (1)
{
bzero (recmsg, BUFLEN + 1);
n = recvfrom (sockfd, recmsg, BUFLEN, 0, (struct sockaddr *) &the_member, &socklen);
if (n < 0)
{
printf ("recvfrom err in udptalk!\n");
exit (4);
}
else{
recmsg[n] = 0;
printf ("recv:[%s]\n\n", recmsg);
printf("ip:%s\n",inet_ntoa(the_member.sin_addr));
printf("port:%d\n", ntohs(the_member.sin_port));
}
cust_uuid = strstr(recmsg, "uuid:"); //获取recmsg字符串中 子字符串"uuid:"的位置
if (cust_uuid == 0)
{
printf("uuid: err!\n");
return 0;
}
cust_uuid += 5; //获取接收的uuid的值
strncpy(uu_buf, cust_uuid, 36);
printf("%s\n",uu_buf);
memset(recmsg,0,sizeof(recmsg));
strcpy(recmsg, aa);
strcat(recmsg, uu_buf);
strcat(recmsg, bb);
if (sendto(sockfd, recmsg, strlen (recmsg), 0, (struct sockaddr *) &the_member, sizeof (the_member)) < 0)
{
printf ("sendto error!\n");
exit (3);
}
printf ("send ok\n");
break;
}
}
Linux下编译运行:
gcc groupcast_discover_server.c -o groupcast_discover_server
./groupcast_discover_server
Windows下安装运行 "ONVIF Device Test Tool"软件,version 12.12,点击Discover Device: