本文主要介绍了gSOAP在c中的详细使用说明,边肖觉得挺好的。现在分享给大家,给大家一个参考。来和边肖一起看看吧。
目录
soap头文件构建客户端应用生成SOAP源代码构建客户端项目构建服务器应用生成SOAP源代码构建服务器项目打印消息SOAP测试项目源代码摘要本文主要介绍了g SOAP在C中的用法,并介绍了SOAP协议的基础知识,适合初次使用g SOAP的开发人员使用。gSOAP官网上的样例代码有些错误,对第一次接触的人不太友好。本文在官方示例calc的基础上做了一些补充和改动。
SOAP简介
SOAP是一个简单的基于 XML 的协议,使得应用程序通过 HTTP 来交换信息。详情请参考SOAP教程。SOAP的本质是通过HTTP协议交换XML格式的数据,但是这种XML格式的定义是被普遍接受的。
使用SOAP时,需要注意的是,由于版本不同(如soapevn、SOAP-ENV),SOAP的XML命名空间可能会有所不同。最好在调用SOAP服务之前确认服务器的XML格式。
gSOAP
gSOAP有两个版本:商业版和开源版。开源版使用GPLv2开源协议,支持多种操作系统。详情请参考github或官网。
GSOAP提供了一套编译工具(可以认为是代码生成器)和一些库文件,以简化用C/C语言开发web服务或客户端程序的工作。开发人员可以专注于实现应用程序的逻辑:
编译器提供了C/C语言的SOAP/XML实现,可以自动完成本地C或C数据类型与XML数据结构之间的转换。
该库提供了SOAP消息的生成,HTTP协议通信的实现,以及最终SOAP消息的生成和传输的相关支持设施。
本文使用的库文件主要是以下几个:
Stdsoap2.h和STD soap 2 . CPP:HTTP协议的实现和最终的SOAP消息生成。如果是C语言,stdsoap2.h和stdsoap2。使用了c。
Typemap.dat: wsdl2h工具在从wsdl文件生成头文件时需要这个文件,并且您可以更改项目的xml名称空间(稍后详细介绍)
Threads.h:实现高性能多线程服务器所需的文件可以并发处理请求,并且不会在服务操作变得耗时时阻塞其他客户端请求。
准备工作
先去官网下载页面,然后选择开源版本:
也可以直接点击开源版本的官方下载链接或者https://pan.baidu.com/s/156PEw9OMbzQel39Oozknow提取代码:gy4x。
将下载的压缩包解压(本文使用的是gsoap_2.8.117.zip),将解压后的文件放在自己习惯的位置(建议放在c盘)。
在命令提示符窗口中,使用cd命令输入..\gsoap_2.8.117\gsoap-2.8\gsoap\bin\win64目录:
注意:后面需要把头文件和typemap.dat放在程序目录下,生成的文件也在这里。
头文件
要使用gSOAP的编译工具生成代码,需要一个定义API的头文件。在这里,官方示例中的头文件calc.h用于两个数的加、减、乘、除或乘:
头文件calc.h可以由wsdl2h工具自动生成(需要Web服务的wsdl文件),cmd命令如下:
wsdl2h-o calc . h http://www.genivia.com/calc.wsdl
您也可以手动定义包含以下内容的calc.h头文件:
//gsoap ns服务方法将两个值相加
int ns__add(双a,双b,双结果);
//gsoap ns服务方法sub减去两个值
int ns__sub(双a,双b,双结果);
//gsoap ns服务方法mul将两个值相乘
int ns__mul(双a,双b,双结果);
//gsoap ns服务方法div划分两个值
int ns__div(双a,双b,双结果);
//gsoap ns服务方法pow将a提升到b
int ns__pow(双a,双b,双结果);
构建客户端应用程序
客户端应用程序在命令行上运行,并使用命令行参数调用calculator Web服务来对两个数字进行加、减、乘、除或乘。
生成soap源码
为客户端生成服务和数据绑定接口:
soapcpp2 -j -r -CL calc.h
其中选项-j生成C代理类,选项-r生成报告,选项-CL仅生成客户端,而没有(未使用的)lib文件。
这会生成以下几个文件:
其中,xml文件是肥皂报文的示例,便于后期的调试,以增加方法为例。
增加方法的请求报文ns.add.req.xml内容如下:
?可扩展标记语言版本='1.0 '编码='UTF八号'?
SOAP-ENV:Envelope
xmlns:SOAP-ENV=' http://模式。XML SOAP。org/SOAP/envelope/'
xmlns:SOAP-ENC=' http://模式。XML SOAP。org/SOAP/encoding/'
xmlns:xsi=' http://。w3。' org/2001/XML架构-实例'
xmlns:xsd=' http://。w3。' org/2001/XML架构'
xmlns:ns=' http://tempuri。组织/国家。xsd '
SOAP-ENV:Body
ns:添加
a0.0/a
b0.0/b
/ns:添加
/SOAP-ENV:Body
/SOAP-ENV:Envelope
增加方法的响应报文ns.add.req.xml内容如下:
?可扩展标记语言版本='1.0 '编码='UTF八号'?
SOAP-ENV:Envelope
xmlns:SOAP-ENV=' http://模式。XML SOAP。org/SOAP/envelope/'
xmlns:SOAP-ENC=' http://模式。XML SOAP。org/SOAP/encoding/'
xmlns:xsi=' http://。w3。' org/2001/XML架构-实例'
xmlns:xsd=' http://。w3。' org/2001/XML架构'
xmlns:ns=' http://tempuri。组织/国家。xsd '
SOAP-ENV:Body
ns:addResponse
结果0.0/结果
/ns:addResponse
/SOAP-ENV:Body
/SOAP-ENV:Envelope
建立客户端项目
建立一个C的控制台应用项目,引入上面生成的几个文件:
soapStub.h:没有注释的纯C/C头文件语法的规范副本。
soapH.h:声明可扩展标记语言序列化程序。
soapC.cpp:实现可扩展标记语言序列化程序。
soapProxy.h:定义客户端可扩展标记语言服务应用程序接口类代理人。
soapProxy.cpp:实现客户端可扩展标记语言服务应用程序接口类代理人。
calc.nsmap: XML命名空间绑定表到#包括。
还需要引入gSOAP解压目录下的stdsoap2.h和stdsoap2.cpp文件。
为方便调试,客户端程序示例改为固定参数调用增加方法,代码如下:
#include 'soapProxy.h '
#包含" ns.nsmap "
/* Web服务端点URL */
const char server[]=' http://localhost:8080 ';
int main(int argc,char** argv)
{
/*if (argc 4)
{
fprintf(stderr,用法:[add | sub | mul | div | pow]num num \ n ');
出口(1);
}*/
代理计算(服务器);
双甲,乙,结果;
/*a=strtod(argv[2],NULL);
b=strtod(argv[3],NULL);*/
a=3;
b=23
/*开关(*argv[1])*/
开关(“甲”)
{
案例“答”:
calc.add(a,b,result);
打破;
案例:
calc sub(a,b,result);
打破;
案例“m”:
calc.mul(a,b,result);
打破;
案例“d”:
calc.div(a,b,result);
打破;
案例“p”:
calc.pow(a,b,result);
打破;
默认值:
fprintf(stderr,未知命令\ n’);
出口(1);
}
如果(计算。肥皂-错误)
计算。soap _ stream _ fault(STD:cerr);
其他
STD:cout ' result=' result STD:endl;
计算。destroy();/*清理*/
STD:cout STD:endl;
返回0;
}
构建服务端应用程序
实现一个独立的迭代服务器,它接受主机端口上的传入请求,支持多线程,可以并发处理请求,并且在服务操作变得耗时时不会阻塞其他客户端请求。
生成SOAP源码
为服务器端生成服务和数据绑定接口:
soapcpp2 -j -r -SL calc.h
其中选项-j生成C服务类,选项-r生成报告,选项-SL仅生成服务器端,而没有(未使用的)lib文件。
生成的文件和客户端的文件名称一样,只是内容不同。
建立服务端项目
建立一个C的控制台应用项目,引入的生成文件和客户端的相同。为了支持多线程,需要引入文件线程。
服务端代码如下:
#包含" soapService.h "
#包含" ns.nsmap "
#include 'threads.h '
int port=8080
无效*流程_请求
{
Service * Service=(Service *)arg;
THREAD _ DETACH(THREAD _ ID);
如果(服务)
{
service-serve();
service-destroy();/*清理*/
删除服务;
}
返回空
}
int main()
{
服务服务(SOAP _ IO _ KEEPALIVE);/*启用HTTP kee-alive */
服务。soap-send _ time out=service。soap-recv _ time out=5;/* 5秒套接字空闲超时*/
服务。soap-transfer _ time out=30;/* 30秒消息传输超时*/
SOAP_SOCKET m=service.bind(NULL,port,100);/*主插座*/
if (soap_valid_socket(m))
{
while(soap _ valid _ socket(service。接受()))
{
线程类型tid
void * arg=(void *)服务。copy();
/*使用更新的THREAD _从插件/线程创建。https://www.genivia.com/files/threads.zip */
如果(参数)
while (THREAD_CREATE(tid,(void *)(void *))process _ request,arg))
睡眠(1);
}
}
服务。soap _ stream _ fault(STD:cerr);
服务。destroy();/*清理*/
返回0;
}
/*服务操作功能*/
int Service:add(双一,双b,双结果)
{
结果=a b;
返回SOAP _ OK
}
/*服务操作功能*/
int Service:sub(双一,双b,双结果)
{
结果=a-b;
返回SOAP _ OK
}
/*服务操作功能*/
int Service:mul(双一,双b,双结果)
{
结果=a * b;
返回SOAP _ OK
}
/*服务操作功能*/
int Service:div(双一,双b,双结果)
{
如果(二)
结果=a/b;
其他
返回soap_senderfault('除以零,NULL);
返回SOAP _ OK
}
/*服务操作功能*/
内部服务:pow(双一,双b,双结果)
{
result=:pow(a,b);
if(soap _ errno==EDOM)/* soap _ errno像错误,但是可移植*/
返回soap_senderfault('幂函数域错误,NULL);
返回SOAP _ OK
}
打印报文
在实际调试中,需要确定肥皂协议过程中具体的报文,只需要改动stdsoap2.cpp源码即可。参考gsoap报文打印,实现保存最后一次报文到特定的文件。
在stdsoap2.h头文件包括下添加fstream,内容如下:
#include 'stdsoap2.h '
#包括fstream
soap_begin_recv函数开始处添加以下代码:
//发送完请求报文获取请求报文信息(作为客户端的时候)
STD:string str _ req XML=“”;
STD:string strBuf;
STD:string:size _ type pos 1=STD:string:NPOs;
STD:string:size _ type pos 2=STD:string:NPOs;
strBuf=soap-buf;
pos1=strBuf.find('?xml ',0);
位置2=strbuf。find('/SOAP-ENV:Envelope ',0);
if (pos1!=std:string:npos pos2!=std:string:npos)
{
str_reqXml=strBuf.substr(pos1,pos 2-pos 1 20);
}
STD:of stream outfile;
文件输出。打开('请求XML。txt’);
outfile str _ reqXml
文件输出。close();
soap_body_end_in函数开始处添加以下代码:
//接收完应答报文获取应答报文信息(作为客户端的时候)
STD:string str _ resXml=" ";
STD:string strBuf;
STD:string strEnd='/SOAP-ENV:Envelope ';
STD:string:size _ type pos 1=STD:string:NPOs;
STD:string:size _ type pos 2=STD:string:NPOs;
pos 1=STD:string:NPOs;
pos 2=STD:string:NPOs;
SOAP-buf[SOAP _ buf len-1]=' \ 0 ';
strBuf=soap-buf;
pos1=strBuf.find('?xml ',0);
pos2=strBuf.find(strEnd,0);
if (pos1!=std:string:npos pos2!=std:string:npos)
{
str_resXml=strBuf.substr(pos1,pos 2-pos 1 strend。length());
}
STD:of stream outfile;
文件输出。打开(' resxml。txt’);
outfile str _ resXml
文件输出。close();
肥皂_接收_原始函数结尾处(返回前)添加以下代码:
//请求报文(作为服务端的时候)
STD:string req _ data;
req_data.assign(soap-buf,ret);
STD:of stream outfile;
文件输出。打开(' req _ data。txt’);
outfile req _ data
文件输出。close();
肥皂_冲洗_原始函数结尾处(返回前)添加以下代码:
//应答报文(作为服务端的时候)
STD:string RES _ data;
res_data.assign(s,n);
STD:of stream outfile;
文件输出。打开(' RES _ data。txt’);
outfile res _ data
文件输出。close();
注:客户端可以一直打印报文,服务端只能在调试运行时才会打印报文,应该有其它方法可以解决。
SOAP测试
运行上面的服务器和客户端项目,可以看到运行API调用的结果,也可以使用SoapUI进行测试。
去官方网站的下载链接:https://www.soapui.org/downloads/soapui/,下载开源版本并安装。
打开软件,在菜单栏的“文件”中选择“新建SOAP项目”:
展开左边的项目,双击“请求”开始测试:
项目源码
SoapTest提取代码:89mu
总结
本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。