Prerequisites
The interfaces defined in the device management and control section of the onvif specification are provided in the form of web services. The onvif specification covers the full definition of XML and WSDL. Each terminal device that supports the onvif specification must provide a web service that corresponds to the function. The Data Interaction Between the server and the client adopts the SOAP protocol. [From http://blog.csdn.net/ghostyu]
Other parts of onvif, such as audio and video streams, are implemented through RTP/RTSP.
What are WebServices, SOAP, WSDL, and gsoap?
If we need to develop an app on Linux, this app needs to interact with the remote web service, such as obtaining an operation result or weather, then we need to use WebServices.
Web services can be summarized as follows:
Web Services can convert applications into network applications.
By using Web Services, applications can publish information to the world or provide a function.
Web Services can be used by other applications.
Through Web Services, the Windows server of the accounting department can be connected to the Unix server of the IT supplier.
The basic Web Services platform is XML + HTTP.
Web Services uses XML to encode and encode data and uses soap to transmit data.
What is SOAP?
Soap is a simple XML-based protocol that allows applications to exchange information over HTTP. Or, more simply, soap is the protocol used to access network services.
For application development, it is very important to enable Internet communication between applications. Currently, applications use Remote Procedure Call (RPC) to communicate with objects such as DCOM and CORBA, but HTTP is not designed for this purpose. RPC may cause compatibility and Security Issues. firewalls and proxy servers usually block such traffic. Communication between applications through HTTP is better because HTTP is supported by all Internet browsers and servers. Soap is created to complete this task. Soap provides a standard method that allows applications running on different operating systems and using different technologies and programming languages to communicate with each other.
How to Implement SOAP?
We need to know that the SOAP protocol is based on XML, so how can we embed them into C/C ++ applications for use?
The gsoap compilation tool provides a SOAP/XML implementation for the C/C ++ language, this makes it much easier to develop Web services or client programs in C/C ++. Hide the content related to the Implementation Details of soap protocols unrelated to development to developers. Because soap provides a standardized method, the gsoap compiler can automatically convert User-Defined localized C or C ++ data types into XML-compliant data structures, in this way, users can be freed from the implementation of soap details by using a set of simple APIs, so that they can focus on the implementation of application logic. It can span multiple operating systems, language environments, and different organizations behind the firewall.
To put it bluntly, gsoap can generate a code framework for developing the soap communication protocol of Web Services. Developers only need to implement the called functions of the server, then, the client can call functions at the remote end just like calling local functions. Gsoap contains two tools, wsdl2h and soapcpp2, to generate a code framework.
To develop a web service program, you need to use gsoap to generate the server and client code framework (generally, you need to implement the server or client, because the other end is usually prepared by others, for example, the onvif in ipnc is implemented on the server side ). We have two methods:
Write the WSDL, use wsdl2h to generate the header file, and then soapcpp2 to generate the Framework Code;
Compile the header file and use soapcpp2 to generate the Framework Code;
The results are the same in both methods. The header file is generated and the code is generated. The difference is that the files to be maintained in project development are different. The former requires to maintain the WSDL file, and the latter maintains the header file.
Soap call example
Next we will use the second method to implement a simple communication instance: Add two numbers at the remote end, and then return the calculation result.
1. Download gSOAP
I'm using version 2.8.8, http://www.kuaipan.cn/file/id_48923272389088693.htm
GSOAP-2.8 software package does not need to be installed, directly decompress, In the gsoap-2.8 \ gsoap \ bin directory is the two aforementioned command line tool, including win32, linux, maxOS and other three versions, when using soapcpp2 to produce code frameworks, files under the gsoap-2.8 \ gsoap \ import directory and gsoap-2.8 \ gsoap \ custom are generally required. Use-I <PATH> in the command line to include it.
2. Compile the header file: add. h
Here we do not need a wsdl file. We can directly generate code from the. h file. We define a function declaration file to define the interface function, named "add. h ".
[Cpp]
View plaincopyprint?
- // Gsoapopt cw
- // Gsoap ns2-schema namespace: urn: add
- // Gsoap nsschema form: unqualified
- // Gsoap int32 service name: add
- // Gsoap ns2-service type: addPortType
- // Gsoap ns2-service port: http://websrv.cs.fsu.edu /~ Engelen/addserver. cgi
- // Gsoap ns2-service namespace: urn: add
- // Gsoap ns2-service transport: http://schemas.xmlsoap.org/soap/http
- // Gsoap ns2-service method-style: add rpc
- // Gsoap int32 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/
- // Gsoap ns2-service method-action: add ""
- Int ns_add (int num1, int num2, int * sum );
// Gsoapopt cw // gsoap ns2-schema namespace: urn: add // gsoap ns2-schema form: unqualified // gsoap nsnsservice name: add // gsoap ns2-service type: addPortType // gsoap ns2-service port: http://websrv.cs.fsu.edu /~ Engelen/addserver. cgi // gsoap nsnsservice namespace: urn: add // gsoap nsnsservice transport: http://schemas.xmlsoap.org/soap/http//gsoap ns2-service method-style: add rpc // gsoap nsnsservice method-encoding: add http://schemas.xmlsoap.org/soap/encoding///gsoap ns2-service method-action: add "" int ns2__ add (int num1, int num2, int * sum);/* Note that there are two consecutive underscores, otherwise, add cannot be found during compilation. nsmap */
3. Generate a code framework
Run the following command to automatically generate some files required for remote calls. (Add them to system environment variables first)
Soapcpp2-c add. h
-C is to generate pure C code, if the prompt does not find typemap. dat, copy the typemap. dat under gsoap-2.8 \ gsoap to the current directory can be. Run the preceding command to obtain the following file:
Remember their names first. They will be mentioned in the future.
4. Add the server code and create the file addserver. c.
[Cpp]
View plaincopyprint?
- # Include "soapH. h"
- # Include "add. nsmap"
- Int main (int argc, char ** argv)
- {
- Int m, s;
- Struct soap add_soap;
- Soap_init (& add_soap );
- Soap_set_namespaces (& add_soap, namespaces );
- If (argc <2 ){
- Printf ("Usage: % S <server_port> \ n", argv [0]);
- Exit (1 );
- } Else {
- M = soap_bind (& add_soap, null, atoi (argv [1]), 100 );
- If (M <0 ){
- Soap_print_fault (& add_soap, stderr );
- Exit (-1 );
- }
- Fprintf (stderr, "Socket connection successful: master socket = % d \ n", m );
- For (;;){
- S = soap_accept (& add_soap );
- If (s <0 ){
- Soap_print_fault (& add_soap, stderr );
- Exit (-1 );
- }
- Fprintf (stderr, "Socket connection successful: slave socket = % d \ n", s );
- Soap_serve (& add_soap );
- Soap_end (& add_soap );
- }
- }
- Return 0;
- }
- # If 1
- Int ns__ add (struct soap * add_soap, int num1, int num2, int * sum)
- {
- * Sum = num1 + num2;
- Return 0;
- }
- # Endif
#include "soapH.h"#include "add.nsmap"int main(int argc, char **argv){ int m, s; struct soap add_soap; soap_init(&add_soap); soap_set_namespaces(&add_soap, namespaces); if (argc < 2) { printf("usage: %s <server_port> \n", argv[0]); exit(1); } else { m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100); if (m < 0) { soap_print_fault(&add_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: master socket = %d\n", m); for (;;) { s = soap_accept(&add_soap); if (s < 0) { soap_print_fault(&add_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: slave socket = %d\n", s); soap_serve(&add_soap); soap_end(&add_soap); } } return 0;}#if 1int ns2__add(struct soap *add_soap, int num1, int num2, int *sum){ *sum = num1 + num2; return 0;}#endif
5. Add the client code and create the file addclient. C.
[Cpp]
View plaincopyprint?
- # Include "soapstub. H"
- # Include "Add. nsmap"
- Int add (const char * server, int num1, int num2, int * sum)
- {
- Struct soap add_soap;
- Int result = 0;
- Soap_init (& add_soap );
- Soap_set_namespaces (& add_soap, namespaces );
- Soap_call_ns__ add (& add_soap, server, NULL, num1, num2, sum );
- Printf ("server is % s, num1 is % d, num2 is % d/n", server, num1, num2 );
- If (add_soap.error ){
- Printf ("soap error: % d, % s, % s \ n", add_soap.error, * soap_faultcode (& add_soap), * soap_faultstring (& add_soap ));
- Result = add_soap.error;
- }
- Soap_end (& add_soap );
- Soap_done (& add_soap );
- Return result;
- }
#include "soapStub.h"#include "add.nsmap"int add(const char *server, int num1, int num2, int *sum){ struct soap add_soap; int result = 0; soap_init(&add_soap); soap_set_namespaces(&add_soap, namespaces); soap_call_ns2__add(&add_soap, server, NULL, num1, num2, sum); printf("server is %s, num1 is %d, num2 is %d/n", server, num1, num2); if (add_soap.error) { printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap)); result = add_soap.error; } soap_end(&add_soap); soap_done(&add_soap); return result;}
6. Write the client test code and create the file addtest. c.
[Cpp]
View plaincopyprint?
- # Include <stdio. h>
- # Include <stdlib. h>
- # Include <string. h>
- Int add (const char * server, int num1, int num2, int * sum );
- Int main (int argc, char ** argv)
- {
- Int result =-1;
- Char server [128] = {0 };
- Int num1;
- Int num2;
- Int sum;
- If (argc <4 ){
- Printf ("usage: % s <ip: port> num1 num2 \ n", argv [0]);
- Exit (1 );
- }
- Strcpy (server, argv [1]);
- Num1 = atoi (argv [2]);
- Num2 = atoi (argv [3]);
- Result = add (server, num1, num2, & sum );
- If (result! = 0 ){
- Printf ("Soap error, errcode = % d \ n", result );
- } Else {
- Printf ("% d + % d = % d \ n", num1, num2, sum );
- }
- Return 0;
- }
#include <stdio.h>#include <stdlib.h>#include <string.h>int add(const char *server, int num1, int num2, int *sum);int main(int argc, char **argv){ int result = -1; char server[128] = {0}; int num1; int num2; int sum; if (argc < 4) { printf("usage: %s <ip:port> num1 num2 \n", argv[0]); exit(1); } strcpy(server,argv[1]); num1 = atoi(argv[2]); num2 = atoi(argv[3]); result = add(server, num1, num2,&sum); if (result != 0) { printf("soap error, errcode=%d\n", result); } else { printf("%d + %d = %d\n", num1, num2, sum); } return 0;}
7. Compile makefile. Before compilation, copy stdsoap2.c and stdsoap2.h under the gsoap-2.8 \ gsoap directory to the current directory, which provides simple calls to the SOAP protocol.
[Cpp]
View plaincopyprint?
- GSOAP_ROOT =/root/onvif/gsoap-2.8/gsoap
- CC = gcc-g-DWITH_NONAMESPACES
- INCLUDE =-I $ (GSOAP_ROOT)
- SERVER_OBJS = soapC. o stdsoap2.o soapServer. o addserver. o
- CLIENT_OBJS = soapC. o stdsoap2.o soapClient. o addclient. o addtest. o
- All: server
- Server: $ (SERVER_OBJS)
- $ (CC) $ (INCLUDE)-o addserver $ (SERVER_OBJS)
- Client: $ (CLIENT_OBJS)
- $ (CC) $ (INCLUDE)-o addtest $ (CLIENT_OBJS)
- Clean:
- Rm-f *. O addtest
GSOAP_ROOT = /root/onvif/gsoap-2.8/gsoapCC = gcc -g -DWITH_NONAMESPACESINCLUDE = -I$(GSOAP_ROOT)SERVER_OBJS = soapC.o stdsoap2.o soapServer.o addserver.o CLIENT_OBJS = soapC.o stdsoap2.o soapClient.o addclient.o addtest.oall: serverserver: $(SERVER_OBJS) $(CC) $(INCLUDE) -o addserver $(SERVER_OBJS) client: $(CLIENT_OBJS) $(CC) $(INCLUDE) -o addtest $(CLIENT_OBJS)clean:rm -f *.o addtest
8. Compile the make server on the server. Compile the client make client to get addserver and addtest.
9. Test
An example of the simplest soap call is completed.
Instance analysis
Server code
Next we will analyze the above example. Just now we just created an add. h header file and declared a function in the add. h header file:
[Cpp]
View plaincopyprint?
- Int ns_add (INT num1, int num2, int * sum );
int ns2__add( int num1, int num2, int* sum );
All other code is generated by a sentence. So where is this entity? Yes, it is in addserver. c that needs to be added by ourselves:
However, it seems that a struct soap parameter is added, which is the global runtime environment of soap. All functions are the first to contain this parameter. Note that the above Makefile, whether it is to compile the server or to compile the client, does not use the add. h file just now. The actual ns_add statement is in the automatically generated soapStub. h.
Then, it is called by the soap_serve_ns_add () function in the automatically generated soapServer. c. In this way, the ns_add function of the real addition operation is linked with the soap code framework. So how can we call this remote function in the client code?
Client code
In addtest. c just added, the main function calls a simple add function.
The implementation of this function is also added by ourselves, in addclient. c:
This function is a bit complicated because it connects the client call with soap. Remember, we copied two files stdsoap2.h and stdsoap2.c when compiling the server and client, soap_init () soap_end () and other functions come from them. Stdsoap2 provides simple operations on the soap protocol, which requires simple function calls to complete remote function calls. Note that soap_call_ns__ add () is also declared in soapStub. h, but it is Client-Side Call Stubs. If you do not understand stub, you can search for rpc.
This function is implemented in the automatically generated soapClient. c source file. We do not need to implement it.
In this way, you can call the ns_add function on the remote host by calling soap_init of stdsoap2 provided by gSOAP and automatically generated soap_call_ns__ add.