由于工作需要,故特意學習了一下gSoap,并記錄下學習筆記,供自己後續複習用。(文中如有任何不對的,請網友指出,本人感激不盡)
下載下傳gSoap工具,下載下傳連結:http://sourceforge.jp/projects/sfnet_gsoap2/releases/
我下載下傳的是,目前最新gsoap_2.8.17版本,由于習慣用windows,下了一個zip檔案,相應的解壓縮後,即可使用。
gSoap簡介
此處引用:http://www.360doc.com/content/13/0121/10/10453810_261511140.shtml
gSOAP編譯工具提供了一個SOAP/XML關于C/C++語言的實作,進而讓C/C++語言開發web服務或用戶端程式的工作變得輕松了很多。絕大多數的C++web服務工具包提供一組API函數類庫來處理特定的SOAP資料結構,這樣就使得使用者必須改變程式結構來适應相關的類庫。與之相反,gSOAP利用編譯器技術提供了一組透明化的SOAP API,并将與開發無關的SOAP實作細節相關的内容對使用者隐藏起來。gSOAP的編譯器能夠自動的将使用者定義的本地化的C或C++資料類型轉變為符合XML文法的資料結構,反之亦然。這樣,隻用一組簡單的API就将使用者從SOAP細節實作工作中解脫了出來,可以專注與應用程式邏輯的實作工作了。gSOAP編譯器可以內建C/C++和Fortran代碼(通過一個Fortran到C的接口),嵌入式系統,其他SOAP程式提供的實時軟體的資源和資訊;可以跨越多個作業系統,語言環境以及在防火牆後的不同組織。
gSOAP使編寫web服務的工作最小化了。gSOAP編譯器生成SOAP的代碼來序列化或反序列化C/C++的資料結構。gSOAP包含一個WSDL生成器,用它來為你的web服務生成web服務的解釋。gSOAP的解釋器及導入器可以使使用者不需要分析web服務的細節就可以實作一個用戶端或服務端程式。
簡言之,gSoap可以為我們生成soap服務端+用戶端代碼的架構,我們隻需要實作具體的接口函數即可。而生成代碼的工具,就是這個gSoap編譯器工具。
gSoap中兩個重要工具介紹
1. wsdl2h
該工具的主要功能是,通過wsdl檔案生成C/C++ .h頭檔案
用法例子:
wsdl2h -o頭檔案名 WSDL檔案名或URL
常用的其它參數:
-o檔案名,指定輸出頭檔案
-n名空間字首 代替預設的ns
-c産生純C代碼,否則是C++代碼
-t檔案名,指定type map檔案,預設為typemap.dat
-e禁止為enum成員加上名空間字首
2. socapcpp2
此工具用來從頭檔案,生成SOAP伺服器及用戶端代碼,還包括WSDL、測試用XML資料
常用選項
-C僅生成用戶端代碼
-S僅生成伺服器端代碼
-L不要産生soapClientLib.c和soapServerLib.c檔案
-c産生純C代碼,否則是C++代碼(與頭檔案有關)
-I指定import路徑
-x不要産生XML示例檔案
-i生成C++包裝,用戶端為xxxxProxy.h(.cpp),伺服器端為xxxxService.h(.cpp)
gSoap例子學習
在gsoap目錄中有個calc的例子,可供我們初學者進行學習。
在D:\gsoap_2.8.17\gsoap-2.8\gsoap\samples\calc++目錄下,另外一個calc是C語言版本,我這用的是C++版本。
1.生成頭檔案
先擷取calc的wsdl檔案,在calc.h中,有 //gsoap ns service namespace: http://websrv.cs.fsu.edu/~engelen/calc.wsdl
該連結就是我們要的wsdl檔案的url.
我在D盤建立了一個calc-demo檔案夾
用wsdl2h.exe生成對應的.h頭檔案(我這邊用的是C++的)
即,wsdl2h.exe–o calc.h對應url,但是會報錯。其實你現在去檢視目錄中的calc.h,對應的内容都已經生成,我實驗過,用該.h運作後續的,沒什麼問題,當然本着“知錯就改”的态度,我們還是要解決下這個問題的。上述問題,是由于缺失typemap.dat檔案所造成,在D:\gsoap_2.8.17\gsoap-2.8\gsoap目錄中,有該typemap.dat檔案,将typemap.dat拷貝到目前目錄calc-demo就可以了,再運作一次,就無錯通過了。生成的calc.h與之前報錯時,生成的是一樣的....
2.生成.cpp及nsmp檔案
得到calc.h頭檔案後,我們需要用soapcpp2.exe,擷取對應的cpp,nsmp檔案
即cmd在目前目錄calc-demo下(生成的檔案都會在該目錄下),指令為:soapcpp2.exe calc.h -I D:\gsoap_2.8.17\gsoap-2.8\gsoap\import
後面的-I D:\gsoap_2.8.17\gsoap-2.8\gsoap\import是因為,編譯中要用到"stlvector.h",該檔案在D:\gsoap_2.8.17\gsoap-2.8\gsoap\import,是以-I向編譯器指定一下該目錄,否則會提示出錯找不到"stlvector.h"檔案。
下圖中紅色框圈起來的,就是soapcpp2.exe新生成出來的,包括服務端、用戶端的cpp都生成出來了。
3. client代碼編寫
在calc-demo目錄下,建立一個控制台工程calc_client,建立檔案client.cpp
client.cpp代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include "calc.nsmap"
#include "stdsoap2.h"
char* g_server="http://localhost:4567";
int sendRequest(const char reqType, double num1, double num2, double &result)
{
struct soap send_soap;
int ret = 0;
soap_init(&send_soap);
switch(reqType)
{
case 'a':
{
soap_call_ns2__add( &send_soap, g_server, "", num1, num2, result );
if(send_soap.error)
{
printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
ret = send_soap.error;
}
else
{
printf("[add] result = %lf\n", result);
}
}
break;
case 's':
{
soap_call_ns2__sub( &send_soap, g_server, "", num1, num2, result );
if(send_soap.error)
{
printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
ret = send_soap.error;
}
else
{
printf("[sub] result = %lf\n", result);
}
}
break;
case 'm':
{
soap_call_ns2__mul( &send_soap, g_server, "", num1, num2, result );
if(send_soap.error)
{
printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
ret = send_soap.error;
}
else
{
printf("[mul] result = %lf\n", result);
}
}
break;
case 'd':
{
soap_call_ns2__div( &send_soap, g_server, "", num1, num2, result );
if(send_soap.error)
{
printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
ret = send_soap.error;
}
else
{
printf("[mul] result = %lf\n", result);
}
}
break;
case 'p':
{
soap_call_ns2__pow( &send_soap, g_server, "", num1, num2, result );
if(send_soap.error)
{
printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
ret = send_soap.error;
}
else
{
printf("[mul] result = %lf\n", result);
}
}
break;
default:
{
printf("not this opertion!\n");
}
break;
}
soap_end(&send_soap);
soap_done(&send_soap);
return ret;
}
int main(int argc, char **argv)
{
int ret = -1;
double num1 = 0;
double num2 = 0;
double result = 0;
if (argc < 4)
{
fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n");
exit(0);
}
num1 = atoi(argv[2]);
num2 = atoi(argv[3]);
ret = sendRequest(*argv[1], num1, num2, result );
return ret;
}
拷貝soapC.cpp、soapClient.cpp、soapH、soapStub.h、calc.nsmap這幾個檔案到檔案夾内。
拷貝D:\gsoap_2.8.17\gsoap-2.8\gsoap目錄下的,stdsoap2.cpp、stdsoap2.h到calc_client檔案夾,并将這幾個檔案都添加到工程中,
注意以下兩點,不然可能會編譯報錯:
在project-setting-Link在Object/librarymodules後添加一個wsock32.lib。
在project-setting中将添加進來的3個源檔案的C/C++選項的Category設定為PrecompiledHeaders。
準備完了,整體編譯下,就OK了。
4. server代碼編寫
在calc-demo目錄下,建立控制台工程calc_server,建立檔案server.cpp
Server.cpp代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "stdsoap2.h"
#include "calc.nsmap"
int main(int argc, char* argv[])
{
int m, s;
struct soap add_soap;
soap_init(&add_soap);
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, server_port = %d/n", m, atoi(argv[1]));
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;
}
int ns2__add(struct soap *add_soap, double num1, double num2, double &result)
{
result = num1 + num2;
printf("[add] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
return 0;
}
int ns2__sub(struct soap *add_soap, double num1, double num2, double &result)
{
if(num1 > num2)
{
result = num1 - num2;
}
else
{
result = num2 - num1;
}
printf("[sub] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
return 0;
}
int ns2__mul(struct soap *add_soap, double num1, double num2, double &result)
{
result = num1 * num2;
printf("[mul] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
return 0;
}
int ns2__div(struct soap *add_soap, double num1, double num2, double &result)
{
result = num1 / num2;
printf("[div] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
return 0;
}
int ns2__pow(struct soap *add_soap, double num1, double num2, double &result)
{
result = pow((float)num1,(float)num2);
printf("[div] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
return 0;
}
拷貝soapC.cpp、soapServer.cpp、soapH、soapStub.h、calc.nsmap這幾個檔案到檔案夾内。
拷貝D:\gsoap_2.8.17\gsoap-2.8\gsoap目錄下的,stdsoap2.cpp、stdsoap2.h到calc_server檔案夾,并将這幾個檔案都添加到工程中。
注意以下兩點,不然可能會編譯報錯:
在project-setting-Link在Object/librarymodules後添加一個wsock32.lib。
在project-setting中将添加進來的3個源檔案的C/C++選項的Category設定為PrecompiledHeaders。
準備完了,整體編譯下,就OK了。
5.調試結果
運作一個cmd跳到D:\calc-demo\calc_server\Debug下輸入calc_server.exe 4567,啟動服務端程式。
(如下圖,在浏覽器中,輸入localhost:4567,能跳出如下頁面,說明服務端已經啟動成功了)
另運作一個cmd跳到D:\calc-demo\calc_client\Debug下輸入calc_client.exe a 6 7,運作用戶端程式。
結果為:[add] result = 13.000000
調試成功。
具體代碼部分,在後面的筆記中,再詳細說明。