C# 调用 C++(gsoap) webservice服务
介绍:webservice 就是远程过程调用,与RPC很像,之前用Linux上的 restRPC调用过C函数接口,webservice也可以支持调用C函数接口,基础可以参考
https://blog.csdn.net/hitzsf/article/details/120669332,按照上面的做完,就可以实现客户端调用服务器的C函数接口。下面介绍C#调用C++的webservice服务。
1、定义头文件 mes.h:
//gsoap ns service name: mesc //gsoap ns service style: rpc //gsoap ns service encoding: utf-8 //gsoap ns service namespace: http://127.0.0.1:8089/mesc.wsdl //gsoap ns service location: http://127.0.0.1:8089/mes //gsoap ns schema namespace: urn:mesc int ns__issueTestTask(std::wstring context, std::wstring &retContext); int ns__add(double a, double b, double *result); int ns__sub(double a, double b, double *result); int ns__mul(double a, double b, double *result); int ns__div(double a, double b, double *result); int ns__pow(double a, double b, double *result);
其中 mesc字符是可以替换的,可以修改为你想要表达的内容,上面的注释是有一定作用的,后面生成文件会采用注释里面的内容(gSoap的文档应该有说明,我没去查看)。
http://127.0.0.1这个IP地址是可以替换的,127.0.0.1作为本机地址,如果两个应用程序都在一台电脑上,是可以调用,但一般情况下不在一台电脑上,所以需要改成自己的IP地址,不然生成的WSDL文件中也会使用这个IP,外机访问就会报错。
然后调用命令行进行预处理,生成依赖文件
soapcpp2.exe -i mes.h
-i参数会成C++的函数接口,不然生成的是C函数接口,C#无法调用。生成的文件列表如下所示:
生成以上文件以后,可以从gsoap的解压包里面,将stdsoap2.h和stdsoap2.cpp拷贝过来,放到同一目录下。
2、搭建C++服务器:生成以上文件后,就可以搭建C++服务器了,我是用的是QtCreator作为集成开发环境,新建一个项目,pro文件如下所示:
QT -= gui CONFIG += c++11 console CONFIG -= app_bundle DEFINES += QT_DEPRECATED_WARNINGS HEADERS += ./webs/soapmescService.h\ ./webs/soapH.h\ ./webs/soapStub.h\ ./webs/stdsoap2.h\ SOURCES += \ main.cpp\ ./webs/soapC.cpp\ ./webs/soapmescService.cpp\ ./webs/stdsoap2.cpp\ OTHER_FILES += ./webs/mesc.nsmap\ ./webs/mesc.wsdl\ INCLUDEPATH += ./webs
其中,webs目录就是刚刚存放mes.h及其生成文件的目录;stdsoap2.h和stdsoap2.cpp是从gSoap的包里面拷贝的(具体请看连接https://blog.csdn.net/hitzsf/article/details/120669332);
main.cpp中的代码如下所示:
#include <QDebug> #include "mesc.nsmap" #include "soapmescService.h" //很重要 int http_get(struct soap *soap) { FILE*fd = NULL; fd = fopen("***************************************\\mesc.wsdl", "rb"); //open WSDL file to copy if (!fd) { return 404; //return HTTP not found error } soap->http_content = "text/xml"; //HTTP header with text /xml content soap_response(soap, SOAP_FILE); for (;;) { size_t r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd); if (!r) { break; } if (soap_send_raw(soap, soap->tmpbuf, r)) { break; //cannot send, but little we can do about that } } fclose(fd); soap_end_send(soap); return SOAP_OK; } int main(int argc, char *argv[]) { mescService cal; cal.fget = http_get; while (1) { if(cal.run(8089)){ cal.soap_stream_fault(std::cerr); } } return 0; } int mescService::issueTestTask(const std::wstring& context, std::wstring &retContext) { QString hello = QString::fromLocal8Bit("你好"); QString end = QString("end"); retContext = hello.toStdWString() + context +end.toStdWString(); return SOAP_OK; } //自动生成了mescService类,自己重写add等函数 /*加法的具体实现*/ int mescService::add(double num1, double num2, double* result) { if (NULL == result) { printf("Error:The third argument should not be NULL!\n"); return SOAP_ERR; } else { (*result) = num1 + num2; return SOAP_OK; } return SOAP_OK; } /*减法的具体实现*/ int mescService::sub(double num1, double num2, double* result) { if (NULL == result) { printf("Error:The third argument should not be NULL!\n"); return SOAP_ERR; } else { (*result) = num1 - num2; return SOAP_OK; } return SOAP_OK; } /*乘法的具体实现*/ int mescService::mul(double num1, double num2, double* result) { if (NULL == result) { printf("Error:The third argument should not be NULL!\n"); return SOAP_ERR; } else { (*result) = num1 * num2; return SOAP_OK; } return SOAP_OK; } /*除法的具体实现*/ int mescService::div(double num1, double num2, double* result) { if (NULL == result || 0 == num2) { return soap_senderfault("Square root of negative value", "I can only compute the square root of a non-negative value"); return SOAP_ERR; } else { (*result) = num1 / num2; return SOAP_OK; } return SOAP_OK; } int mescService::pow(double num1, double num2, double* result) { if (NULL == result || 0 == num2) { printf("Error:The second argument is 0 or The third argument is NULL!\n"); return SOAP_ERR; } else { (*result) = num1 / num2; return SOAP_OK; } return SOAP_OK; }
说明:http_get这个函数一定要写并且需要使用,不然C#那端收不到说明信息。
如此,运行即可启动服务。
下面讲解C#端的代码:
启动Vs,新建一个空的C#工程,在“引用”那边右键,添加web服务引用,输入http://127.0.0.1:8089/,就可自动导入服务所提供的接口(注意服务一定要启动,OS:不知道是不是应为C#和C++都是面向对象的可以直接调用,C#无法直接调用C接口,参数不提示)。C#工程的代码如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ConsoleApplication1.ServiceReference; namespace RectangleApplication { class ExecuteRectangle { static void Main(string[] args) { mescPortTypeClient service = new mescPortTypeClient(); double sum = service.add(1, 2); string retContext = service.issueTestTask("中文测试"); Console.WriteLine("web issueTestTask : {0}", retContext); Console.WriteLine("web Sum : {0}", sum); Console.ReadLine(); } } }
启动客户端程序,即可远程调用服务。