gSOAP下载地址:https://sourceforge.net/projects/gsoap2/files/
相关配置参考:gsoap_2.8.33.zip安装与编译
配置完成后,根据官网文档:https://www.genivia.com/dev.html
编写一个hello进行测试
新建文件 hello.h
// hello.h
int ns__hello(std::string name, std::string& greeting);
终端运行 soapcpp2 hello.h
,如果你不在此程序的路径,则输入完整路径编译
如 /usr/local/gSOAP/bin/soapcpp2 hello.h
然后我们新建 hello.cpp
// hello.cpp
#include "soapH.h" // include the generated source code headers
#include "ns.nsmap" // include XML namespaces
int main()
{
return soap_serve(soap_new());
}
int ns__hello(struct soap *soap, std::string name, std::string& greeting)
{
greeting = "Hello " + name;
return SOAP_OK;
}
终端运行 c++ -o hello.cgi hello.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
报错如下
没有stdsoap2.cpp这个文件
这个文件可以在gSOAP解压后的文件夹里找到 gsoap-2.8/gsoap
我们将 stdsoap2.cpp 和 stdsoap2.h 这两个文件拷贝到源程序的目录,再次执行
c++ -o hello.cgi hello.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
编译完成 生成 hello.cgi 。
看到 cgi程序,我就想到了之前我用的BOA,那么我们来试试看吧。
BOA相关参考:嵌入式web服务器BOA+CGI+HTML+MySQL项目实战——Linux
老规矩 运行boa
sudo ./boa
将 cgi程序放在 /var/www/cgi-bin 目录下
然后在浏览器访问我们的网址 http://localhost:886/cgi-bin/hello.cgi
效果如下:
一个SOAP的XML,SOAP相关知识可以参考:SOAP菜鸟教程
回到官方文档 如何实现和部署gSOAPWeb服务API。其教程:传送门
终端运行 wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
同样,我的是
/usr/local/gSOAP/bin/wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
继续根据教程走
终端运行 soapcpp2 -SL calc.h
同样,我的是 /usr/local/gSOAP/bin/soapcpp2 -SL calc.h
很顺利哈,我们继续。
官方教程让我们运行 cc -o calc.cgi calccgi.c soapClient.c soapC.c stdsoap2.c
Linux 下 的 cc 和 gcc
这cc是个啥?我运行后。。。
又缺少文件了 后者我还能理解,前者这个文件从哪来的?
在哪也找不到 calccgi.c 这个文件,后来看了文档发现,官方提供了 此文件的超链接。。。
那么我们 从 https://www.genivia.com/files/calccgi.c 复制代码,自建一个 calccgi.c 文件。
/*
calccgi.c
Example calculator service in C
Compilation in C (see samples/calc/calc.h):
$ wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
$ soapcpp2 -SL calc.h
$ cc -o calc.cgi calccgi.c stdsoap2.c soapC.c soapServer.c
where stdsoap2.c is in the 'gsoap' directory, or use libgsoap:
$ cc -o calc.cgi calccgi.c soapC.c soapServer.c -lgsoap
--------------------------------------------------------------------------------
gSOAP XML Web services tools
Copyright (C) 2001-2017, Robert van Engelen, Genivia, Inc. All Rights Reserved.
This software is released under one of the following two licenses:
GPL or Genivia's license for commercial use.
--------------------------------------------------------------------------------
GPL license.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
Author contact information:
[email protected] / [email protected]
--------------------------------------------------------------------------------
A commercial use license is available from Genivia, Inc., [email protected]
--------------------------------------------------------------------------------
*/
#include "soapH.h"
#include "calc.nsmap"
int main(int argc, char **argv)
{
struct soap soap;
soap_init1(&soap, SOAP_XML_INDENT);
soap_serve(&soap); /* serve as CGI application */
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
return 0;
}
int ns2__add(struct soap *soap, double a, double b, double *result)
{
(void)soap;
*result = a + b;
return SOAP_OK;
}
int ns2__sub(struct soap *soap, double a, double b, double *result)
{
(void)soap;
*result = a - b;
return SOAP_OK;
}
int ns2__mul(struct soap *soap, double a, double b, double *result)
{
(void)soap;
*result = a * b;
return SOAP_OK;
}
int ns2__div(struct soap *soap, double a, double b, double *result)
{
if (b)
*result = a / b;
else
{
char *s = (char*)soap_malloc(soap, 1024);
(SOAP_SNPRINTF(s, 1024, 100), "Can't divide %f by %f ", a, b);
return soap_sender_fault(soap, "Division by zero", s);
}
return SOAP_OK;
}
int ns2__pow(struct soap *soap, double a, double b, double *result)
{
*result = pow(a, b);
if (soap_errno == EDOM) /* soap_errno is like errno, but compatible with Win32 */
{ char *s = (char*)soap_malloc(soap, 1024);
(SOAP_SNPRINTF(s, 1024, 100), "Can't raise %f to %f ", a, b);
return soap_sender_fault(soap, "Power function domain error", s);
}
return SOAP_OK;
}
那么现在我们还缺少 soapClient.c,我们之前生成了 soapClient.cpp 文件
打开项目文件夹,我发现一个很尴尬的事情,我们生成了server的c和cpp文件,但client却只有c。
我无语了,那我就自建 soapClient.c,拷贝soapClient.cpp贴入soapClient.c。
再次运行 cc -o calc.cgi calccgi.c soapClient.c soapC.c stdsoap2.c
报错如下:
果然没有那么容易,看到 std::string,这事情不简单了。
我们重新执行 /usr/local/gSOAP/bin/soapcpp2 calc.h
成功生成了 soapClient.c 文件了
但为什么官方提供的命令是加个 -SL ?
我查看了下载来的gSOAP文档:太平洋那下载的,自行斟酌
我们机翻一下看看, -S -L 是干什么的
只生成服务器端代码,官方教程为什么要这么做,不知道为啥,既然我们现在生成好了,我们再编译看看,终端运行 cc -o calc.cgi calccgi.c soapClient.c soapC.c stdsoap2.c
事情还是没有那么顺利,又报错了。
我们试试官网的 calc.h 的源码贴入看看
再次执行 /usr/local/gSOAP/bin/soapcpp2 calc.h
没有效果呀  ̄へ ̄
会看之前的hello.cpp 却没有报错,区别就是c和cpp?
在 soapServer.cpp 中
soapServer.c 中
而 soapClient.c和cpp压根没这函数???
那我们加入 soapServer.c 一起编译!
cc -o calc.cgi calccgi.c soapClient.c soapC.c stdsoap2.c soapServer.c
(⊙ˍ⊙) 错误消失了。。。 我服了
pow函数大家应该都比较熟悉,链接 pow 所在的数学库 libm
cc -o calc.cgi calccgi.c soapClient.c soapC.c stdsoap2.c soapServer.c -lm
总算过去了! ╥﹏╥…
抛到BOA看看
和hello.cgi 一样。
回到官方教程
我事先已经装好了Apache,那我们继续往下走
要编译C服务器:
cc -o calcserver.cgi calcserver.c soapC.c soapServer.c stdsoap2.c
恩,calcserver.c 这文件又没有。同样官方给了链接,进去看看:传送门
这 typemap.dat 在gSOAP中可以搜到,我们先手动建个 calc.h
//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);
其他都不管,来到client
新建 calcclient.c
#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;
}
使用以下方法为客户端生成服务和数据绑定接口:
soapcpp2 -c -r -CL calc.h
有产生警告,暂时不管。
构建示例客户端应用程序
cc -o calcclient calcclient.c stdsoap2.c soapC.c soapClient.c
没有问题。
新建 calcserver.c
#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服务相同,但在循环中通过套接字进行服务请求调度除外:
#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;
}
...
/* service operation functions */
...
这个暂且忽略,我们往下走
使用以下方法为服务器端生成服务和数据绑定接口:
soapcpp2 -c -r -SL calc.h
cc -o calcserver calcserver.c stdsoap2.c soapC.c soapServer.c
修改为 cc -o calcserver calcserver.c stdsoap2.c soapC.c soapServer.c -lm
官方教程接近尾声
根据官方教程 我们执行 calcclient程序 ./calcclient add 2 3
成功计算出结果了。恩 这和 calcserver 有关系吗?
我们删了 calcserver 看看,恩 你会发现 还是能输出结果。。。
回到前一个教程
要编译C服务器:
cc -o calcserver.cgi calcserver.c soapC.c soapServer.c stdsoap2.c
同样我们加上 -lm
cc -o calcserver.cgi calcserver.c soapC.c soapServer.c stdsoap2.c -lm
我们直接执行这条命令看看 ./calcserver.cgi < calc.add.req.xml
这将显示自动生成的示例soap/xml消息的服务响应。calc.add.req.xml
那依照教程,将 cgi 放在cgi-bin 下,我的是BOA
我们提供浏览器访问看看
效果还是一样。
那差不多就这样结束了,官方教程还有一大堆,可自行查阅:传送门
目录:
我们看看别人的案例试试 gsoap_2.8.33.zip安装与编译
add.h
复制过来运行发现有问题,改为
//gsoapopt cw
//gsoap ns2 schema namespace: urn:add
//gsoap ns2 schema form: unqualified
//gsoap ns2 service name: add
//gsoap ns2 service type: addPortType
//add http://schemas.xmlsoap.org/soap/encoding/
//gsoap ns2 service method-action: add ""
int ns2__add( int num1, int num2, int* sum );
int ns2__sub( int num1, int num2, int *sub);
然后 执行 /usr/local/gSOAP/bin/soapcpp2 -c add.h
#include
#include
#include "soapH.h"
#include "add.nsmap"
int main(int argc, char **argv)
{
int m, s;
struct soap add_soap;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, namespaces);
if (argc < 2) {
printf("usage: %s /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\n", m);
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, int num1, int num2, int *sum)
{
*sum = num1 + num2;
return 0;
}
int ns2__sub(struct soap *sub_soap, int num1, int num2, int *sub)
{
*sub = num1 - num2;
return 0;
}
#include
#include
#include "soapStub.h"
#include "add.nsmap"
int add(const char *server, int num1, int num2, int *sum);
int sub(const char *server, int num1, int num2, int *sub);
int main(int argc, char **argv)
{
int result = -1;
char server[128] = {0};
int num1;
int num2;
int sum;
if (argc < 4) {
printf("usage: %s num1 num2 /n" , argv[0]);
exit(1);
}
strcpy(server,argv[1]);
num1 = atoi(argv[2]);
num2 = atoi(argv[3]);
result = add(server, num1, num2, &sum);
if (result != 0) {
printf("soap error, errcode=%d\n", result);
} else {
printf("%d + %d = %d\n", num1, num2, sum);
}
result = sub(server, num1, num2, &sum);
if (result != 0) {
printf("soap error, errcode=%d\n", result);
} else {
printf("%d - %d = %d\n", num1, num2, sum);
}
return 0;
}
int add(const char *server, int num1, int num2, int *sum)
{
struct soap add_soap;
int result = 0;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, namespaces);
soap_call_ns2__add(&add_soap, server, NULL, num1, num2, sum);
printf("server is %s, num1 is %d, num2 is %d\n", server, num1, num2);
if (add_soap.error) {
printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap));
result = add_soap.error;
}
soap_end(&add_soap);
soap_done(&add_soap);
return result;
}
int sub(const char *server, int num1, int num2, int *sub)
{
struct soap add_soap;
int result = 0;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, namespaces);
soap_call_ns2__sub(&add_soap, server, NULL, num1, num2, sub);
printf("server is %s, num1 is %d, num2 is %d\n", server, num1, num2);
if (add_soap.error) {
printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap));
result = add_soap.error;
}
soap_end(&add_soap);
soap_done(&add_soap);
return result;
}
stdsoap2.c 和 stdsoap2.h,在gSOAP里面搜出来,拷贝过来,上文已经准备好了
新建 Makefile
直接复制过来多半是不行的,看到第一行 GSOAP_ROOT ,根目录改成自己的,那我应该是如下
GSOAP_ROOT = /home/hlx/gsoap-2.8/gsoap
WSNAME = add
CC = g++ -g -DWITH_NONAMESPACES
INCLUDE = -I $(GSOAP_ROOT)
SERVER_OBJS =soapC.o stdsoap2.o soapServer.o $(WSNAME)server.o
CLIENT_OBJS =soapC.o stdsoap2.o soapClient.o $(WSNAME)client.o
all: server
server: $(SERVER_OBJS)
$(CC) $(INCLUDE) -o $(WSNAME)server $(SERVER_OBJS)
client: $(CLIENT_OBJS)
$(CC) $(INCLUDE) -o $(WSNAME)client $(CLIENT_OBJS)
clean:
rm -f *.o *.xml *.a *.wsdl *.nsmap soap* $(WSNAME)Stub.* $(WSNAME)server ns.xsd $(WSNAME)test
终端执行
make server
make client
我make挂了,tab分割符,不能用空格,我们修改一下。
make完毕。编译生成服务端执行程序 addserver 和客户端执行程序 addclient
终端执行 ./addserver 8888
运行服务端程序
终端打印出“Socket connection successful: master socket = 3”,那么你的server已经在前台run起来了
新建另一终端执行客户端程序 ./addclient http://localhost:8888 99 22
成功计算了加减法,服务端也有所响应。
案例结束
引自:gsoap_2.8.33.zip安装与编译 作者:拿破仑的海阔天空
大佬博客链接:ONVIF协议网络摄像机(IPC)客户端程序开发(4):使用gSOAP生成Web Services框架代码
我新建了个code,大佬是在Windows下的,所以那2个exe我没拷贝,其他同理拷贝,建立文件夹
然后我们终端执行
/usr/local/gSOAP/bin/wsdl2h -o mobilecode.h -c -s -t typemap.dat http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
有警告,暂时忽略。生成了 mobilecode.h
其中-c为产生纯c代码,默认生成 c++代码;-s为不使用STL库,-t为typemap.dat的标识。详情可通过wsdl2h.exe -help查看帮助。
这里的WSDL文件,可以在wsdl2h命令中在线下载,也可以先下载到本地,然后引用本地WSDL文件,这里是采用在线下载方式。 —— 引自 https://blog.csdn.net/benkaoya/article/details/72452968
终端执行 /usr/local/gSOAP/bin/soapcpp2 -C -c -x -Iimport -Icustom mobilecode.h
custom、import、wsdl2h.exe、soapcpp2.exe、typemap.dat、mobilecode.h、soapClientLib.c 无用,可以删除。删除后
新建 main.c
#include
#include
#include
#include "soapStub.h"
#include "MobileCodeWSSoap.nsmap"
void getMobileCodeInfo(char *mobileCode)
{
struct soap *soap = NULL;
const char *endpoint = "http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx";
struct _ns1__getMobileCodeInfo req;
struct _ns1__getMobileCodeInfoResponse resp;
soap = soap_new();
// allocate and initalize a context
soap_set_mode(soap, SOAP_C_UTFSTRING);
// support multibyte string(for Chinese)
memset(&req, 0x00, sizeof(req));
req.mobileCode = mobileCode;
req.userID = NULL;
if(SOAP_OK == soap_call___ns1__getMobileCodeInfo(soap, endpoint, NULL, &req, &resp)) {
if (NULL != resp.getMobileCodeInfoResult) {
printf("%s\n", resp.getMobileCodeInfoResult);
}
}
soap_destroy(soap); // delete deserialized objects
soap_end(soap); // delete allocated data
soap_free(soap); // free the soap struct context data
}
int main(int argc, char **argv)
{
if (argc < 2) {
return 0;
}
getMobileCodeInfo(argv[1]);
return 0;
}
大佬突然就运行了,我们Linux的话 编译 gcc main.c stdsoap2.c soapC.c soapClient.c
然后 ./a.out 手机号码
随便百度个手机号码看看
我们终端执行 ./a.out 18937777777
运行结果出来了,大佬的博客也结束了,大佬的ONVIF栏目 传送门 大家可自行查阅。
恩 我们的文章到此结束了,真是漫长的旅程。各位有缘再见。O(∩_∩)O~~
gsoap下载:https://sourceforge.net/projects/gsoap2/
gsoap主页:http://www.cs.fsu.edu/~engelen/soap.html
gsoap官网: http://gsoap2.sourceforge.net/
官方教程:https://www.genivia.com/tutorials.html
gSOAP资料下载-太平洋下载中心(自行斟酌):https://dl.pconline.com.cn/download/1448138.html
gsoap_2.8.33.zip安装与编译:https://blog.csdn.net/hktkfly6/article/details/78321908
SOAP菜鸟教程:https://www.runoob.com/soap/soap-tutorial.html
WSDL 教程:https://www.w3school.com.cn/wsdl/index.asp
ONVIF协议解读:https://blog.csdn.net/hktkfly6/article/details/78322154
ONVIF协议学习笔记:https://www.cnblogs.com/lsdb/p/9157302.html
ONVIF大佬博客:https://blog.csdn.net/benkaoya/category_6924052.html