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

启动客户端程序,即可远程调用服务。

 

posted on 2022-08-22 18:06  明太宗朱棣  阅读(244)  评论(0编辑  收藏  举报

导航