天天看點

gSoap例子學習(一)

由于工作需要,故特意學習了一下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++的)

gSoap例子學習(一)
gSoap例子學習(一)

即,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檔案

gSoap例子學習(一)
gSoap例子學習(一)

即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都生成出來了。

gSoap例子學習(一)

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,能跳出如下頁面,說明服務端已經啟動成功了)

gSoap例子學習(一)
gSoap例子學習(一)
gSoap例子學習(一)

另運作一個cmd跳到D:\calc-demo\calc_client\Debug下輸入calc_client.exe a 6 7,運作用戶端程式。

gSoap例子學習(一)
gSoap例子學習(一)

結果為:[add] result = 13.000000

調試成功。

具體代碼部分,在後面的筆記中,再詳細說明。