介紹: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();
        }
    }
}

啓動客户端程序,即可遠程調用服務。