According to wikipedia "A Web service is a method of communication between two electronic devices over the Web (Internet)." I would not say over the 'Web', indeed you can communicate within a local area network without the need on going 'Web'.
On this tutorial we are going to explain step by step how to deploy a Web Service on our Rasberry. We are also going to see how to develop a little application in our laptop that will communicate with this Web Service.
The protocol used on a web service is called 'SOAP' and is based on 'XML'. The following diagram explains in a simplified way how a Web Service communication is carried out.
The most common usage of Web Services is via HTTP, and that is the reason behind its popularity. In fact all the existing web infrastructure (from routers to web servers) fits perfectly on this model, without the need of adapt absolutely anything.
How the xml is formed, is specified on the SOAP protocol. Normally the commercial Web Services API, like the ones used on .Net, Java, or C++, hide the complexity of the protocol, so we can focus on our object s model and the 'dirty' work of converting those object on 'XML' (and viceversa) is completely transparent for us.
1. Downloading GSoap.
GSoap is a open source Web Service API, written in C and C++. You can download the last version from here.
There are 2 important tools shipped on the download, the one that we are going to use is called 'soapcpp2' and you can find it on the following path:
./gsoap-2.8/gsoap/bin/linux386/soapcpp2
2. Defining our service interface.
On this example we are going to create a service that returns the hour from our Raspberry.
The service interface is defined in a similar way than a library interface. We are going to create a header defining the method that will be called:
2. Generating the server classes.
Now that our service is defined, we have to generate the classes that will handle the request. Fortunately this can be done automatically by using 'soapcpp2'. Go to your project path (in my case ~/workspace/workspace64/GSoapTuto/MyRaspberryTimeServer/src) and execute soapcpp2 with the following options:
~/Desktop/GSoap/gsoap-2.8/gsoap/bin/linux386/soapcpp2 -S currentTime.h
-S indicates server-side only files
If everything went ok, several files should have been added to your project:
Remove the files 'soapcurrentTimeService.cpp' and 'soapcurrentTimeService.h', and add the files 'stdsoap2.cpp' and 'stdsoap2.h'. You can find these last on the downloaded package (/gsoap-2.8/gsoap).
2. Creating a standalone server.
We are almost done with the server, we just need to create a new file 'currentTime.cpp' and create the 'main' method and define what must be done when 'ns__currentTime' is called.
currentTime.cpp code:
#include "soapH.h" // include the generated declarations
#include "currentTime.nsmap" // include the XML namespace mappings
int main()
{
struct soap soap;
int m, s; // master and slave sockets
soap_init(&soap);
m = soap_bind(&soap, "192.168.1.54", 2012, 100);
if (m < 0)
soap_print_fault(&soap, stderr);
else
{
fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
for (int i = 1; ; i++)
{
s = soap_accept(&soap);
if (s < 0)
{
soap_print_fault(&soap, stderr);
break;
}
fprintf(stderr, "%d: accepted connection from IP=%d.%d.%d.%d socket=%d", i,
(soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF, s);
if (soap_serve(&soap) != SOAP_OK) // process RPC request
soap_print_fault(&soap, stderr); // print error
fprintf(stderr, "request served\n");
soap_destroy(&soap); // clean up class instances
soap_end(&soap); // clean up everything and close socket
}
}
soap_done(&soap); // close master socket and detach context
}
int ns__currentTime(struct soap *soap, time_t& response)
{
response = time(0);
return SOAP_OK;
}
You will have to change the line 'm = soap_bind(&soap, "192.168.1.54", 2012, 100);' and set the IP of your Raspberry (192.168.1.54 in my case) and the port you want it to listen from (2012 in my case).
If you want to make the resultant program work on Raspberry, you will have to cross-compile it. You can do it by changing the properties of your project and performing the following changes:
Under GCC C++ Compiler, change Command: 'g++' by 'arm-linux-gnueabi-g++'
Under GCC C++ Linker, change Command: 'g++' by 'arm-linux-gnueabi-g++'
You can find more information about cross-compilation for Raspberry on my previous post here.
2. Executing the server on Raspberry
The last thing we have to do is to copy the resultant compiled into Raspberry:
And finally, execute it:
3. Developing the client:
Now that we have a Web Service deployed on our RaspBerry, lets communicate with it. The steps to build the client are quite similar to the ones we followed to build the server.
First, we create a client project, containing exactly the same header definition than the one we used for the server (you can copy-paste the file).
From the project src path (~/workspace/workspace64/GSoapTuto/MyRaspberryTimeClient/src in my case), execute the following command to generate the code for the client:
~/Desktop/GSoap/gsoap-2.8/gsoap/bin/linux386/soapcpp2 -i -C currentTime.h
Add the 'stdsoap2.cpp' and 'stdsoap2.h' as we did for the server. And finally add 'currentTime.cpp' including the main method with the following content:
On this tutorial we are going to explain step by step how to deploy a Web Service on our Rasberry. We are also going to see how to develop a little application in our laptop that will communicate with this Web Service.
The protocol used on a web service is called 'SOAP' and is based on 'XML'. The following diagram explains in a simplified way how a Web Service communication is carried out.
Fig.1 Simplified SOAP exchange diagram
The most common usage of Web Services is via HTTP, and that is the reason behind its popularity. In fact all the existing web infrastructure (from routers to web servers) fits perfectly on this model, without the need of adapt absolutely anything.
How the xml is formed, is specified on the SOAP protocol. Normally the commercial Web Services API, like the ones used on .Net, Java, or C++, hide the complexity of the protocol, so we can focus on our object s model and the 'dirty' work of converting those object on 'XML' (and viceversa) is completely transparent for us.
1. Downloading GSoap.
GSoap is a open source Web Service API, written in C and C++. You can download the last version from here.
There are 2 important tools shipped on the download, the one that we are going to use is called 'soapcpp2' and you can find it on the following path:
./gsoap-2.8/gsoap/bin/linux386/soapcpp2
2. Defining our service interface.
On this example we are going to create a service that returns the hour from our Raspberry.
The service interface is defined in a similar way than a library interface. We are going to create a header defining the method that will be called:
Fig. 2 Sevice Definition header |
2. Generating the server classes.
Now that our service is defined, we have to generate the classes that will handle the request. Fortunately this can be done automatically by using 'soapcpp2'. Go to your project path (in my case ~/workspace/workspace64/GSoapTuto/MyRaspberryTimeServer/src) and execute soapcpp2 with the following options:
~/Desktop/GSoap/gsoap-2.8/gsoap/bin/linux386/soapcpp2 -S currentTime.h
-S indicates server-side only files
If everything went ok, several files should have been added to your project:
Fig 3. Auto generated code |
2. Creating a standalone server.
We are almost done with the server, we just need to create a new file 'currentTime.cpp' and create the 'main' method and define what must be done when 'ns__currentTime' is called.
Fig 4. Resultant file structure |
currentTime.cpp code:
#include "soapH.h" // include the generated declarations
#include "currentTime.nsmap" // include the XML namespace mappings
int main()
{
struct soap soap;
int m, s; // master and slave sockets
soap_init(&soap);
m = soap_bind(&soap, "192.168.1.54", 2012, 100);
if (m < 0)
soap_print_fault(&soap, stderr);
else
{
fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
for (int i = 1; ; i++)
{
s = soap_accept(&soap);
if (s < 0)
{
soap_print_fault(&soap, stderr);
break;
}
fprintf(stderr, "%d: accepted connection from IP=%d.%d.%d.%d socket=%d", i,
(soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF, s);
if (soap_serve(&soap) != SOAP_OK) // process RPC request
soap_print_fault(&soap, stderr); // print error
fprintf(stderr, "request served\n");
soap_destroy(&soap); // clean up class instances
soap_end(&soap); // clean up everything and close socket
}
}
soap_done(&soap); // close master socket and detach context
}
int ns__currentTime(struct soap *soap, time_t& response)
{
response = time(0);
return SOAP_OK;
}
You will have to change the line 'm = soap_bind(&soap, "192.168.1.54", 2012, 100);' and set the IP of your Raspberry (192.168.1.54 in my case) and the port you want it to listen from (2012 in my case).
If you want to make the resultant program work on Raspberry, you will have to cross-compile it. You can do it by changing the properties of your project and performing the following changes:
Under GCC C++ Compiler, change Command: 'g++' by 'arm-linux-gnueabi-g++'
Under GCC C++ Linker, change Command: 'g++' by 'arm-linux-gnueabi-g++'
You can find more information about cross-compilation for Raspberry on my previous post here.
2. Executing the server on Raspberry
The last thing we have to do is to copy the resultant compiled into Raspberry:
fig 5. Copy the resultant program to raspberry using scp |
And finally, execute it:
Fig 6. Raspberry serving our service |
3. Developing the client:
Now that we have a Web Service deployed on our RaspBerry, lets communicate with it. The steps to build the client are quite similar to the ones we followed to build the server.
First, we create a client project, containing exactly the same header definition than the one we used for the server (you can copy-paste the file).
From the project src path (~/workspace/workspace64/GSoapTuto/MyRaspberryTimeClient/src in my case), execute the following command to generate the code for the client:
~/Desktop/GSoap/gsoap-2.8/gsoap/bin/linux386/soapcpp2 -i -C currentTime.h
Add the 'stdsoap2.cpp' and 'stdsoap2.h' as we did for the server. And finally add 'currentTime.cpp' including the main method with the following content:
Fig 7. Resultant client structure |
Finally, on change the line 'soap_endpoint = "http://www.yourdomain.com/currentTime.cgi";' on the file 'soapcurrentTimeProxy.cpp' in order to target your Raspberry:
soap_endpoint = "http://192.168.1.54:2012"; in my case
And that's all!! If you fulfilled all the steps, after compiling and executing your client, you should get a beautiful result like 'The time is 1342473837' indicating the date in seconds from your Raspberry.
If you have a look to the Raspberry console, it should display some info about the just served request:
Fig 8. First Raspberry served request!! |