现在的位置: 首页 > 综合 > 正文

GSoap简单使用

2014年08月29日 ⁄ 综合 ⁄ 共 4750字 ⁄ 字号 评论关闭
      公司业务需要,用到Soap同WebService对接。本来想使用MS soap toolkit,但是这东东用到的系统的XML解析库,在不同的windows平台下存在冲突,虽然能规避解决,但觉得不完美,转用gsoap微笑。本文简单的介绍VC++ 2010下使用Gsoap生成客户端程序,以及本人遇到的问题,使用的资源,阅读前还是要了解下soap协议(自己也只是知道点皮毛)。

1、资料
下载地址
http://sourceforge.net/projects/gsoap2/
官网
http://genivia.com/Products/gsoap/index.html
官方学习教程
http://genivia.com/Products/gsoap/documentation.html

2、使用VS2010创建简单WebService
2.1 创建工程
New project --> Visual C# --> ASP.Net Empty Web Application

2.2 添加WebServices
Add New Item --> Web Service

2.3 WebService代码
修改了下原有代码,加法接口

namespace WebApplication_Test
{
    /// <summary>
    /// Summary description for WebService1
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class WebService1 : System.Web.Services.WebService
    {
        [WebMethod]
        public double TestAdd(double a, double b)
        {
            return a + b;
        }
    }
}

2.4 运行结果

http://localhost:12676/WebService1.asmx

作为服务器的链接地址

3 使用Gsoap生成代码
这里使用gsoap_2.8.17版本,最新的请到官网中下载。
用到.\gsoap-2.8\gsoap\bin\win32
wsdl2h.exe 根据WebService生成.h文件,其中描述了soap服务器的接口等,可以通过doxygen来获得头文件信息。
cmd窗口运行命令:

wsdl2h.exe -o head.h http://localhost:12676/WebService1.asmx?WSDL

-o 指定需要输出的头文件,默认为当前目录
head.h 为输出的.h文件
http://localhost:12676/WebService1.asmx?WSDL 为服务器地址+?WSDL

soapcpp2.exe 解析头文件,生成相应的源代码,运行:

soapcpp2.exe -C -i -x head.h -I ../../Import

常用命令
-C 仅生成客户端代码
-S 仅生成服务器端代码
-c 产生纯C代码,否则是C++代码(与头文件有关)
-I 指定import路径,导入../../Import(不导入会失败)
-x 不要产生XML示例文件
-i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。

生成最终文件如下:

其中xxxProxy.h、xxxProxy.cpp即为客户端类代码
对于应用程序,需要使用到的为
soapC.cpp、soapH.h、soapStub.h、soapWebService1SoapProxy.cpp、soapWebService1SoapProxy.h、WebService1Soap.nsmap
以及 ../../stdsoap2.cpp、../../stdsoap2.h

4 生成客户端程序
4.1 简单的创建MFC对话框程序
4.2 添加以上soap文件
由于MFC默认要求CPP文件包含stdafx.h头文件,针对soapC.cpp、soapWebService1SoapProxy.cpp、stdsoap2.cpp,直接编译会提示

1>soap\soapC.cpp(16): warning C4627: '#include "soapH.h"': skipped when looking for precompiled header use
1>          Add directive to 'StdAfx.h' or rebuild precompiled header
1>soap\soapC.cpp(2119): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?
1>  soapWebService1SoapProxy.cpp
1>soap\soapWebService1SoapProxy.cpp(11): warning C4627: '#include "soapWebService1SoapProxy.h"': skipped when looking for precompiled header use
1>          Add directive to 'StdAfx.h' or rebuild precompiled header
1>soap\soapWebService1SoapProxy.cpp(221): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?
1>  stdsoap2.cpp
1>soap\stdsoap2.cpp(895): warning C4244: 'return' : conversion from 'std::streamsize' to 'size_t', possible loss of data

可手动修改添加头文件,或者修改编译条件

4.3 调用webService
响应OnOK程序,代码如下

#include "soapWebService1SoapProxy.h"
#include "WebService1Soap.nsmap"
void CTestSoapCPlusPlusDlg::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	//CDialogEx::OnOK();
	WebService1SoapProxy mySoap;
	_ns1__TestAdd stuParam;
	stuParam.a = 10.0;
	stuParam.b = 100.0;
	_ns1__TestAddResponse stuResponse;

	//! 调用
	char szSever[] = "http://localhost:12676/WebService1.asmx?wsdl";
	if (SOAP_OK == mySoap.TestAdd(szSever, NULL, &stuParam, &stuResponse))
	{
		CString strMsg;
		strMsg.Format("result:%.2f", stuResponse.TestAddResult);
		MessageBox(strMsg);
	}
	else
	{
		CString strMsg;
		strMsg.Format("result:%s", mySoap.soap_fault_string());
		MessageBox(strMsg);
	}
}

注意包含文件
soapWebService1SoapProxy.h,WebService1Soap.nsmap
其中:
szServer指定服务器,如果不明确指定,则使用默认服务器

OK,大功告成

5 碰到的问题
5.1 nafxcw.lib 同 LIBCMT.lib冲突

1>  TestSoapDlg.cpp
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.obj)
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.obj)
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new[](unsigned int)" (??_U@YAPAXI@Z) already defined in libcpmt.lib(newaop.obj)
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete[](void *)" (??_V@YAXPAX@Z) already defined in LIBCMT.lib(delete2.obj)
1>J:\C++\Soap\gSoap\Program\TestSoap\Release\TestSoap.exe : fatal error LNK1169: one or more multiply defined symbols found
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:06.67
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

原因:
nafxcw是MFC运行链接库libcmt是C运行库,编译器先链接了libcmt,再链接nafxcw,导致符号重复定义,具体参见
http://support.microsoft.com/kb/148652/zh-cn
解决:
将两个库都忽略,再按顺序添加,编译器将根据指定的顺序执行链接
注意:
Debug版本下两个库为 nafxcwd.lib、LIBCMTD.lib
Release版本下两个库为 nafxcw.lib、LIBCMT.lib
不注意可能会出现很坑的错误。。。。

5.2 stdSoapC.cpp 无法解析的外部符号_namespace

原因:
nsmap包含错误,该文件是namespace map,定义了个namespaces变量,在stdSoap.cpp中有
5.3 传输中文时,出现乱码
解决(原因没深入):
初始化WebService1SoapProxy类时,使用构造函数
/// Constructor with engine input+output mode control
WebService1SoapProxy(soap_mode iomode);
设置iomode为
SOAP_C_UTFSTRING
6 相关程序文件
包括websevices、客户端、gsoap文件,见

http://download.csdn.net/detail/otosu/6953421

抱歉!评论已关闭.