The onvif client implements discovery and device search.

Source: Internet
Author: User
Tags socket error

One method is to use the gsoap library WS-discovery, and the other is to directly write a socket multicast message.

The first method is convenient to parse XML and customize XML, and the messages sent are also the Standard Discovery protocol,

This method can receive an XML response, but it cannot be solved! Now you have to parse this part by yourself.

Second, you need to write the XML by yourself and learn more about the protocol.

The third method is to directly generate the soap_recv ___ TDN _ ********** type generated in onvif WSDL. This is the same as the first method, and XML cannot be parsed.

A: The onvif gsoap client uses WS-discovery

To use gsoap for discovery, follow these steps:

1: used files (described in the gsoap WS-discovery 2.8 stable manual)
Plugin directory
Threads. c
Threads. h
Wssaapi. c
Wssaapi. h
Wsddapi. c
Wsddapi. h

Import directory
WSDD. h

2: Use the WS-Discovery.wsdl In the WS directory to generate code (of course, The remotediscovery of onvif can also be used, but the generated is very large)
./Wsdl2h-cgye-O discovery. h-t WS-typemap.dat WS-Discovery.wsdl
./Soapcpp2-C-2-N-pdiscovery discovery. H-I ../import

3: some code modifications
After completing step 1, some code is generated. You need to modify the reference of a header file in wsddapi. h.

Wsddapi. H and wsaapi. h contains a # include "soaph. H ", soaph is the default generated name, because in step 2, I changed the name of the generated code file to discovery, which is the soapcpp2-N option.
Therefore, wsddap. h # include "soaph. H" must be changed to # include "discoveryh. H"

Also changed the generated file: soap_namespace_of_wsdd in discoverystub. h.
Original:
# Define soap_namespace_of_wsdd "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01"

Changed:

# Define soap_namespace_of_wsdd "http://schemas.xmlsoap.org/ws/2005/04/discovery"

Because I compared it with the onvif test tool, and this is different from the one generated above, I changed it.

4: How to Implement WSDD
This is also mentioned in the gsoap WS-discovery 2.8 stable manual:
The following method: it is equivalent to the event processing function. For example, after sending HELLO, The wsdd_event_hello method will be called.

Void wsdd_event_probematches (struct soap * soap, unsigned int instanceid, const char * sequenceid, unsigned int
Messagenumber, const char * messageid, const char * relatesto, struct WSDD _ probematchestype * matches)
{
Return;
}

Void wsdd_event_resolvematches (struct soap * soap, unsigned int instanceid, const char * sequenceid, unsigned int
Messagenumber, const char * messageid, const char * relatesto, struct WSDD _ resolvematchtype * match)
{
Return;

}

Void wsdd_event_hello (struct soap * soap, unsigned int instanceid, const char * sequenceid, unsigned int messagenumber,
Const char * messageid, const char * relatesto, const char * endpointreference, const char * types, const char * scopes, const
Char * matchby, const char * xaddrs, unsigned int metadataversion)
{
Return;
}

Void wsdd_event_bye (struct soap * soap, unsigned int instanceid, const char * sequenceid, unsigned int messagenumber, const
Char * messageid, const char * relatesto, const char * endpointreference, const char * types, const char * scopes, const char
* Matchby, const char * xaddrs, unsigned int * metadataversion)
{
Return;
}

Soap_wsdd_mode wsdd_event_probe (struct soap * soap, const char * messageid, const char * replyto, const char * types, const
Char * scopes, const char * matchby, struct WSDD _ probematchestype * matches)
{
Printf ("messageid: % s", messageid );
Return soap_wsdd_managed;
}

Soap_wsdd_mode wsdd_event_resolve (struct soap * soap, const char * messageid, const char * replyto, const char
* Endpointreference, struct WSDD _ resolvematchtype * match)
{
Return soap_wsdd_managed;
}

5: Use in gosap
The above content should be ready for use. Because it is multicast, you must set it during sending.
Soap. connect_flags = so_broadcast;

As shown in the following figure, enable-ddebug during partial translation. You can see the received message in the Recv. log directory.
Int main (){
Struct soap;

Char * msg_uuid = NULL;
Soap_set_namespaces (& soap, namespaces );
Soap_init (& soap );
Msg_uuid = soap_wsa_rand_uuid (& soap );

Soap. connect_flags = so_broadcast;
Printf ("msg_uuid: % s \ n", msg_uuid );

Soap_wsdd_probe (& soap, soap_wsdd_managed, soap_wsdd_to_ts, "Soap. UDP: // 239.00000000250: 3702", msg_uuid, null, ds_types, "", null );

For (I = 0; I <10; I ++ ){
Soap_recv ___ WSDD _ probe (& soap, & __ WSDD _ probe_recv );
Sleep (1 );
}

Soap_destroy (& soap );
Soap_end (& soap );
Soap_done (& soap );

}

An XML message is received. You can define a callback for gsoap as follows:

Int recv_callback (struct soap * gsoap, char * XML, int Len ){
Printf ("XML: % s \ n", XML );
Return 0;
}

Soap. frecv = recv_callback;

Alternatively, call soap_wsdd_probe to read soap. Buff.

The above process may be recorded later, with less details.
Soap_wsdd_probe is to fill the body and header content, while soap_send ___ WSDD _ probe is to send the buff out, some friends directly call soap_send ___ WSDD _ probe, therefore, the XML sent is an empty body.

B: write your own socket to send messages:If we use the above method, we don't need to write any code or something. If we write a message sent by multicast, it seems simpler and the generated code is much smaller: use the following method to send multicast messages:

Int sendtomt (){
Int ret;
Int S;
Int I = 1;
Char buffer [2048] = {0 };
Struct sockaddr_in multi_addr; // multicast address
Struct sockaddr_in client_addr;
S = socket (af_inet, sock_dgram, 0); // create a datagram socket
If (S <0 ){
Perror ("socket error ");
Return-1;
}
Multi_addr.sin_family = af_inet;
Multi_addr.sin_port = htons (mcast_port); // multicast Port
Multi_addr.sin_addr.s_addr = inet_addr (mcast_addr); // multicast address

// Send data to multicast groups


Int size = sendto (S, buff_define, strlen (buff_define), 0, (struct sockaddr *) & multi_addr, sizeof (multi_addr ));
If (size <0 ){
Perror ("sendto error ");
}
Sleep (1 );
I ++;
Int Len = sizeof (client_addr );
For (I = 0; I <10; I ++ ){
Memset (buffer, 0, sizeof (buffer ));
Memset (& client_addr, 0, sizeof (struct sockaddr ));
Size = recvfrom (S, buffer, 2047,0, (struct sockaddr *) & client_addr, & Len );
Printf ("=================: % s, % d ====================== I: % d =======\ nbuffer: % s \ n ", inet_ntoa (client_addr.sin_addr), ntohs (client_addr.sin_port), I, buffer );
Sleep (1 );
}
Close (s );
}

The content to be sent must be changed according to your actual needs:
Char * buff_define = "<? XML version = \ "1.0 \" encoding = \ "UTF-8 \"?> \
<Envelope \
Xmlns: DN = \ "http://www.onvif.org/ver10/network/wsdl \"\
Xmlns = \ "http://www.w3.org/2003/05/soap-envelope\"> \
<Header> \
<WSA: messageid xmlns: WSA = \ "http://schemas.xmlsoap.org/ws/2004/08/addressing\"> UUID: 4e7ca33c-1f95-4cba-a05a-
0079b3ba927f </WSA: messageid> \
<WSA: To xmlns: WSA = \ "http://schemas.xmlsoap.org/ws/2004/08/addressing\"> urn: Schemas-xmlsoap-
Org: WS: 2005: 04: discovery </WSA: To> \
<WSA: Action
Xmlns: WSA = \ "http://schemas.xmlsoap.org/ws/2004/08/addressing\"> http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe </WSA:
Action> \
</Header> \
<Body> \
<Probe \
Xmlns: xsi = \ "http://www.w3.org/2001/xmlschema-instance \"\
Xmlns: XSD = \ "http://www.w3.org/2001/xmlschema \"\
Xmlns = \ "http://schemas.xmlsoap.org/ws/2005/04/discovery\"> \
<Types> dn: networkvideotransmitter </types> \
<Scopes/> \
</Probe> \
</Body> \
</Envelope> ";

The trouble with this method is that you still need to parse the received XML, but we can find a lightweight XML library to do it, because you do not need to rewrite the XML, this library can parse XML content.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.