介紹:webservice 就是遠程過程調用,與RPC很像,之前用Linux上的 restRPC調用過C函數接口,webservice也可以支持調用C函數接口,基礎可以參考
,按照上面的做完,就可以實現客户端調用服務器的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的文檔應該有説明,我沒去查看)。
然後調用命令行進行預處理,生成依賴文件
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的包裏面拷貝的(具體請看連接);
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();
}
}
}
啓動客户端程序,即可遠程調用服務。