当前位置: 首页 > news >正文

Calculator客户端和服务器示例

概述:
此示例在C中实现了一个简单的SOAP / XML API客户端和服务器。

Web服务规范示例
计算器XML Web服务calc.h在gSOAP soapcpp2工具要处理的文件中指定。该calc.h规范定义了五个计算器方法add,sub,mul,div和pow:

//gsoap ns service name: calc Simple calculator service described at https://www.genivia.com/dev.html //gsoap ns service protocol: SOAP //gsoap ns service style: rpc //gsoap ns service encoding: encoded //gsoap ns service namespace: http://websrv.cs.fsu.edu/~engelen/calc.wsdl //gsoap ns service location: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi //gsoap ns schema namespace: urn:calc //gsoap ns service method: add Sums two values int ns__add(double a, double b, double *result); //gsoap ns service method: sub Subtracts two values int ns__sub(double a, double b, double *result); //gsoap ns service method: mul Multiplies two values int ns__mul(double a, double b, double *result); //gsoap ns service method: div Divides two values int ns__div(double a, double b, double *result); //gsoap ns service method: pow Raises a to b int ns__pow(double a, double b, double *result);

此示例calc.h文件是手动定义的。可以通过在一个或多个Web服务的WSDL上运行wsdl2h命令来自动获取具有Web服务规范的这些特殊“头文件”:

wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl

这是calc.h从指定的WSDL calc.wsdl文件生成的。

在运行wsdl2h之前,我们建议修改typemap.dat以将XML名称空间前缀绑定到wsdl2h将使用的名称空间URI。由于此服务使用URI“urn:calc”,并且我们希望将其绑定到ns前缀,因此我们应将以下行添加到typemap.dat:

ns = "urn:calc"

要从WSDL获取名称空间URI,请在WSDL上运行wsdl2h,然后从生成的头文件中检索它们(它们位于顶部)。然后在添加要与命名空间关联的前缀名称后重新运行wsdl2h命令typemap.dat。

关于Web服务规范语法的一些注释
gSOAP“头文件”中的Web服务规范定义了服务和数据绑定接口。该规范使用带有指令和注释的普通C / C ++语法。

C / C ++类型和成员的XML名称空间限定是通过带有双下划线的C / C ++标识符命名约定来完成的,就像ns__add将前缀绑定ns到add。也可以使用冒号ns:add(ns:用soapcpp2剥离)。
@ 用于声明应该序列化为XML属性的struct和class成员。
数据成员的缺省值可以=直接在struct或class声明中赋值。
XML元素和属性出现约束minOccurs:maxOccurs在结构或类成员声明的末尾声明为表单。
XML元素重复是STL容器或动态数组。动态数组是一对大小字段和数组指针成员,例如$int size; struct ns__employee_record *manages是size指向的长度数组manages。
XML Web服务操作被声明为函数,其中最后一个参数是指向结果值的指针或引用。使用结构或类返回多个值。
这些//gsoap指令用于绑定XML名称空间并定义SOAP Web服务属性:

//gsoap prefix service name: <WSDLserviceName> <documentationText> //gsoap prefix service style: [rpc|document] //gsoap prefix service encoding: [literal|encoded] //gsoap prefix service namespace: <WSDLnamespaceURI> //gsoap prefix service location: <WSDLserviceAddressLocationURI>

绑定Web服务操作属性:

//gsoap prefix service method-style: <methodName> [rpc|document] //gsoap prefix service method-encoding: <methodName> [literal|encoded] //gsoap prefix service method-action: <methodName> <actionString> //gsoap prefix service method-documentation: <methodName> <documentation>

要定义类型架构属性:

//gsoap prefix schema namespace: <schemaNamespaceURI> //gsoap prefix schema elementForm: [qualified|unqualified] //gsoap prefix schema attributeForm: [qualified|unqualified] //gsoap prefix schema documentation: <documentationText> //gsoap prefix schema type-documentation: <typeName> <documentationText>

这里prefix是C / C ++名称中使用的XML名称空间前缀,例如nsin ns__add。

具有服务和数据绑定接口的Web服务规范由soapcpp2处理以生成服务和数据绑定实现代码,请参阅下面的构建步骤。

实现客户端应用程序
客户端应用程序calcclient.c在命令行运行,并使用命令行参数调用计算器Web服务来添加,减去,乘,除或增加两个浮点数的幂:

#include "soapH.h" #include "calc.nsmap" /* the Web service endpoint URL */ const char server[] = "http://websrv.cs.fsu.edu/~engelen/calcserver.cgi"; int main(int argc, char **argv) { struct soap *soap = soap_new1(SOAP_XML_INDENT); /* new context */ double a, b, result; if (argc < 4) { fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n"); exit(1); } a = strtod(argv[2], NULL); b = strtod(argv[3], NULL); switch (*argv[1]) { case 'a': soap_call_ns__add(soap, server, "", a, b, &result); break; case 's': soap_call_ns__sub(soap, server, "", a, b, &result); break; case 'm': soap_call_ns__mul(soap, server, "", a, b, &result); break; case 'd': soap_call_ns__div(soap, server, "", a, b, &result); break; case 'p': soap_call_ns__pow(soap, server, "", a, b, &result); break; default: fprintf(stderr, "Unknown command\n"); exit(1); } if (soap->error) soap_print_fault(soap, stderr); else printf("result = %g\n", result); soap_destroy(soap); /* delete deserialized objects */ soap_end(soap); /* delete heap and temp data */ soap_free(soap); /* we're done with the context */ return 0; }

请参阅有关如何使用HTTP代理和HTTPS 的教程。

构建客户端应用程序的步骤
为客户端生成服务和数据绑定接口:

soapcpp2 -c -r -CL calc.h

其中option -c生成C代码,option -r生成报告,option只-CL生成客户端而没有(未使用的)lib文件。

这会生成多个文件,包括:

soapStub.h 没有注释的普通C / C ++头文件语法规范的副本。 soapH.h 声明XML序列化程序。 soapC.c 实现XML序列化程序。 soapClient.c 实现客户端XML服务API。 calc.nsmap XML命名空间绑定表到#include soapReadme.md 服务和数据绑定接口详细信息。

要构建示例客户端应用程序,我们还需要stdsoap2.h和stdsoap2.c:

gcc -o calcclient calcclient.c stdsoap2.c soapC.c soapClient.c

实现CGI服务器应用程序
CGI服务器应用程序calcserver.c实现服务操作并接受stdin soap_serve(soap)上的请求,将请求分派给这五个服务操作之一:

#include "soapH.h" #include "calc.nsmap" int main() { struct soap *soap = soap_new(); /* new context */ soap_serve(soap); /* serve CGI request */ soap_destroy(soap); /* delete deserialized objects */ soap_end(soap); /* delete heap and temp data */ soap_free(soap); /* we're done with the context */ return 0; } /* service operation function implementation */ int ns__add(struct soap *soap, double a, double b, double *result) { *result = a + b; return SOAP_OK; } /* service operation function implementation */ int ns__sub(struct soap *soap, double a, double b, double *result) { *result = a - b; return SOAP_OK; } /* service operation function implementation */ int ns__mul(struct soap *soap, double a, double b, double *result) { *result = a * b; return SOAP_OK; } /* service operation function implementation */ int ns__div(struct soap *soap, double a, double b, double *result) { if (b) *result = a / b; else return soap_sender_fault(soap, "Division by zero", NULL); return SOAP_OK; } /* service operation function implementation */ int ns__pow(struct soap *soap, double a, double b, double *result) { *result = pow(a, b); if (soap_errno == EDOM) /* soap_errno is like errno, but portable */ return soap_sender_fault(soap, "Power function domain error", NULL); return SOAP_OK; }

使用下面进一步讨论的构建步骤构建服务应用程序后,将CGI应用程序安装在Web服务器的cgi-bin文件夹中。

实现独立的服务器应用程序
此示例显示了一个独立的迭代服务器,它接受主机端口上的传入请求。该程序与CGI服务相同,除了通过循环中的套接字调度服务请求:

#include "soapH.h" #include "calc.nsmap" int port = 8080; int main() { SOAP_SOCKET m; /* master socket */ struct soap soap = soap_new(); /* new context */ soap->send_timeout = soap->recv_timeout = 5; /* 5 sec socket idle timeout */ soap->transfer_timeout = 30; /* 30 sec message transfer timeout */ m = soap_bind(soap, NULL, port), 1); /* backlog=1 for iterative servers, multi-threaded services should use 100 */ if (soap_valid_socket(m)) { while (soap_valid_socket(soap_accept(soap))) { soap_serve(soap); /* serve request */ soap_destroy(soap); /* delete deserialized objects */ soap_end(soap); /* delete heap and temp data */ } } soap_print_fault(soap, stderr); soap_destroy(soap); /* delete deserialized objects */ soap_end(soap); /* delete heap and temp data */ soap_free(soap); /* we're done with the context */ return 0; }

注意:只要接受失败,此服务器就会退出。最好是在发生短期连接问题时添加一些逻辑以继续。

为了提高性能,我们应该实现一个多线程服务器,它可以同时处理请求,并且在服务操作变得耗时时不会阻止其他客户端请求:

#include "soapH.h" #include "calc.nsmap" #include "plugin/threads.h" int port = 8080; void *process_request(void *arg) { struct soap *soap = (struct soap*)arg; THREAD_DETACH(THREAD_ID); if (soap) { soap_serve(soap); soap_destroy(soap); soap_end(soap); soap_free(soap); } return NULL; } int main() { SOAP_SOCKET m; /* master socket */ struct soap *soap = soap_new1(SOAP_IO_KEEPALIVE); /* new context with HTTP keep-alive enabled */ soap->send_timeout = soap->recv_timeout = 5; /* 5 sec socket idle timeout */ soap->transfer_timeout = 30; /* 30 sec message transfer timeout */ m = soap_bind(soap, NULL, port), 100); if (soap_valid_socket(m)) { while (soap_valid_socket(soap_accept(soap))) { THREAD_TYPE tid; void *arg = (void*)soap_copy(soap); /* use updated THREAD_CREATE from plugin/threads.h https://www.genivia.com/files/threads.zip */ if (arg) while (THREAD_CREATE(&tid, (void*(*)(void*))process_request, arg)) sleep(1); } } soap_print_fault(soap, stderr); soap_destroy(soap); /* delete deserialized objects */ soap_end(soap); /* delete heap and temp data */ soap_free(soap); /* we're done with the context */ return 0; }

此服务器对可生成的线程数没有限制,因此您可能希望保持受互斥锁保护的计数器不超过最大值。此外,使用线程池可以提高整体性能。最好是使用ISAPI和Apache模块来开发gSOAP用户指南中建议的强大而安全的服务。

请参阅有关如何使用线程池,启用HTTPS以及如何强化独立服务的教程。
请参阅有关如何使用ISAPI和Apache模块开发服务的文档。

构建服务器应用程序的步骤
使用以下命令为服务器端生成服务和数据绑定接口:

soapcpp2 -c -r -SL calc.h

其中option -c生成C代码,option -r生成报告,option只-SL生成服务器端而没有(未使用的)lib文件。

这会生成多个文件,包括:

soapStub.h 没有注释的普通C / C ++头文件语法规范的副本。 soapH.h 声明XML序列化程序。 soapC.c 实现XML序列化程序。 soapServer.c 实现服务器端XML服务API。 calc.nsmap XML命名空间绑定表到#include soapReadme.md 服务和数据绑定接口详细信息。

要构建示例服务器应用程序,我们还需要stdsoap2.h和stdsoap2.c:

gcc -o calcserver calcserver.c stdsoap2.c soapC.c soapServer.c

运行示例
./calcclient add 2 3
result = 5
要在端口8080上对独立服务器运行该示例,请更改server[] = “http://localhost:8080”。

http://www.jsqmd.com/news/1281931/

相关文章:

  • Flutter 工程构架设计(MVVM + Repository)
  • mysql学习之旅(十三)——Mysql的存储引擎
  • SAM2-UNet论文复现
  • 南昌地热地板哪家强?口碑好的制造厂推荐 - GrowthUME
  • 2026新版三明防水补漏服务商参考|阳台渗漏修缮方案指南 - 筑宅安
  • Ubuntu smba 重启
  • 26年医护考试App多维参考:发展趋势动态追踪 - 虚拟星辰
  • 2026最新AI写小说工具测评:实测10款写小说ai软件,新手如何开始写小说?
  • 如何高效构建智能游戏自动化引擎:M9A图像识别框架深度指南
  • 基于PLC的恒温恒湿控制系统设计与实现
  • 解析请求体内容(如 JSON、表单数据、XML 等) 将原始数据转换为 Python 数据结构 使转换后的数据可在 request. ...
  • 美团LongCat-2.0 MoE模型解析:ASIC训练与OpenRouter实践指南
  • 平芯微HY2120-CB高精度检测+自恢复+0V电池激活充电
  • MongoDB 4.2——在生产环境中设置 MongoDB
  • 2026找深圳市电动升降柱厂家推荐,防撞升降柱厂家哪家好?本地优质源头厂选购指南:5个坑+5条硬标准 - GEO99
  • 微山县油罐厂家哪家好,撬装油罐厂家推荐怎么选不踩坑?2026避坑攻略与靠谱厂家推荐 - GEO99
  • 基于Spring Boot的高校新生报到系统设计与优化实践
  • 2026年3款苹果短视频工具免费额度实测对比,哪款才是实用王者
  • 2026年7月苏州预付卡消费纠纷维权路径与法律分析 - 速递信息
  • 塑料滤水板生产企业推荐指南(2026 招投标完整版) - 排水板厂家
  • 三相电压不平衡的危害诊断与工程解决方案
  • LangChain对话上下文管理:原理与实践指南
  • 2026年东莞除甲醛行业深度观察:三大口碑品牌对比 - 环保除醛知识库
  • SQL注入实战指南:从手工注入到自动化工具,CTFHub靶场通关与安全防御
  • 音视频编解码——视频数据格式
  • WeNet语音识别工具包与LibriSpeech数据集实战指南
  • Flask构建在线教育平台:技术选型与核心实现
  • 伊利亚·苏茨克维尔的SSI获得英伟达Vera Rubin平台访问权
  • 彩笔运维勇闯机器学习--拟合
  • 泉州除甲醛优选名单:绿舒环保等6家深度测评 - 绿舒环保母婴除甲醛