【问题标题】:Axis2C unofficial vs. Axis2C StaffAxis2C 非官方与 Axis2C 员工
【发布时间】:2013-09-04 21:48:21
【问题描述】:

我将开发一个应用程序,该应用程序将使用一些基于 SOAP 的 Web 服务框架。我做了一些研究,我有点喜欢 Axis2C 框架,但在某些主题中,我发现最初的 Axis2C 实现存在内存泄漏,并且它的官方开发已经停止。

幸运的是,存在 Axis2C 非官方分支以及基于 Axis2C 的 Staff 框架。现在,问题是,这些 Axis2C 后代中的哪个更好或更容易使用?我知道,Staff 用 C++ 封装了 Axis2C,但我不介意纯 C。Staff 是否也修复了内存泄漏?

感谢您的建议。

【问题讨论】:

    标签: c++ soap frameworks axis2c


    【解决方案1】:

    我不能告诉你 Axis2/C 的工作已经停止,它还在继续进行,但非常非常缓慢。如果你查看trunk repo,你可以看到今年只有 5 次提交……Trunk 版本 1.7.0(未发布)有很多变化和新功能,但发布日期仍然未知。

    原来的 Axis2/C-1.6.0 确实存在内存泄漏和已知问题,不适合生产。 Axis2/C-unofficial 基于原始 Axis2/C-1.6.0 并修复了大多数关键问题并提供了其他有用的功能。 但是非官方的分支,当然和原来的 API 是一样的,你会花同样的时间来开发服务或客户端。 使用起来并不容易或难。

    如果我们谈论 WSF Staff,它旨在快速开发 WEB 服务和客户端。与 Axis2/C 相比,您只需编写几行代码即可启动服务或客户端工作。您不需要了解内部消息结构:您只使用简单的(bool、int、string 等)或复杂的(struct、typedef、std 容器...)类型(当然您可以使用低-级别访问消息)。 Axis2/C 有类似的特性,名为 ADB(Axis 数据绑定),但它是通过 C-way 完成的,您需要编写额外的代码行来访问请求和结果。

    请注意 ADB(和生成的服务)存在内存泄漏,并且在非官方分支中未修复。

    为了比较哪个更容易使用 - ADB 或 Staff 我想举这个例子:

    注意:{}之间的代码需要手动编写。

    Axis2/C 示例中实现Calculator 服务加法操作的方式没有ADB(传统):

    axiom_node_t *
    axis2_calc_add(
        const axutil_env_t * env,
        axiom_node_t * node)
    {
        axiom_node_t *param1_node = NULL;
        axiom_node_t *param1_text_node = NULL;
        axis2_char_t *param1_str = NULL;
        long int param1 = 0;
        axiom_node_t *param2_node = NULL;
        axiom_node_t *param2_text_node = NULL;
        axis2_char_t *param2_str = NULL;
        long int param2 = 0;
    
        if (!node)
        {
            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INPUT_OM_NODE_NULL,
                            AXIS2_FAILURE);
            printf("Calculator client request ERROR: input parameter NULL\n");
            return NULL;
        }
    
        /* iterating to the first child element skipping (empty) text elements */
        for (param1_node = axiom_node_get_first_child(node, env);
             param1_node && axiom_node_get_node_type(param1_node, env) != AXIOM_ELEMENT;
             param1_node = axiom_node_get_next_sibling(param1_node, env));
    
        if (!param1_node)
        {
            AXIS2_ERROR_SET(env->error,
                            AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                            AXIS2_FAILURE);
            printf("Calculator service  ERROR: invalid XML in request\n");
            return NULL;
        }
        param1_text_node = axiom_node_get_first_child(param1_node, env);
        if (!param1_text_node)
        {
            AXIS2_ERROR_SET(env->error,
                            AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                            AXIS2_FAILURE);
            printf("Calculator service  ERROR: invalid XML in request\n");
            return NULL;
        }
        if (axiom_node_get_node_type(param1_text_node, env) == AXIOM_TEXT)
        {
            axiom_text_t *text =
                (axiom_text_t *) axiom_node_get_data_element(param1_text_node, env);
            if (text && axiom_text_get_value(text, env))
            {
                param1_str = (axis2_char_t *) axiom_text_get_value(text, env);
            }
        }
        else
        {
            AXIS2_ERROR_SET(env->error,
                            AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                            AXIS2_FAILURE);
            printf("Calculator service ERROR: invalid XML in request\n");
            return NULL;
        }
    
        /* iterating to the second child element skipping (empty) text elements */
        for (param2_node = axiom_node_get_next_sibling(param1_node, env);
             param2_node && axiom_node_get_node_type(param2_node, env) != AXIOM_ELEMENT;
             param2_node = axiom_node_get_next_sibling(param2_node, env));
        if (!param2_node)
        {
            AXIS2_ERROR_SET(env->error,
                            AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                            AXIS2_FAILURE);
            printf("Calculator service  ERROR: invalid XML in request\n");
            return NULL;
        }
        param2_text_node = axiom_node_get_first_child(param2_node, env);
        if (!param2_text_node)
        {
            AXIS2_ERROR_SET(env->error,
                            AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                            AXIS2_FAILURE);
            printf("Calculator service  ERROR: invalid XML in request\n");
            return NULL;
        }
        if (axiom_node_get_node_type(param2_text_node, env) == AXIOM_TEXT)
        {
            axiom_text_t *text =
                (axiom_text_t *) axiom_node_get_data_element(param2_text_node, env);
            if (text && axiom_text_get_value(text, env))
            {
                param2_str = (axis2_char_t *) axiom_text_get_value(text, env);
            }
        }
        else
        {
            AXIS2_ERROR_SET(env->error,
                            AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                            AXIS2_FAILURE);
            printf("Calculator service ERROR: invalid XML in request\n");
            return NULL;
        }
    
        if (param1_str && param2_str)
        {
            long int result = 0;
            axis2_char_t result_str[255];
    
            axiom_element_t *ele1 = NULL;
            axiom_node_t *node1 = NULL,
                *node2 = NULL;
            axiom_namespace_t *ns1 = NULL;
            axiom_text_t *text1 = NULL;
    
            param1 = strtol(param1_str, NULL, 10);
            param2 = strtol(param2_str, NULL, 10);
            result = param1 + param2;
            sprintf(result_str, "%ld", result);
    
            ns1 = axiom_namespace_create(env,
                                         "http://axis2/test/namespace1", "ns1");
            ele1 = axiom_element_create(env, NULL, "result", ns1, &node1);
            text1 = axiom_text_create(env, node1, result_str, &node2);
    
            return node1;
        }
    
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_OPERATION_PARAMETERS_IN_SOAP_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service ERROR: invalid parameters\n");
        return NULL;
    }
    

    Axis2/C 代码生成示例中实现计算器服务 WITH ADB 的添加操作的 Axis2/C 方式:

        adb_addResponse_t * axis2_skel_Calculator_add(const axutil_env_t * env,
                                                        adb_add_t * add) 
    {
        adb_addResponse_t * add_res = NULL;
        int ret_val = 0;
        int val1 = 0;
        int val2 = 0;
        val1 = adb_add_get_arg_0_0(add, env);
        val2 = adb_add_get_arg_1_0(add, env);
        ret_val = val1 + val2;
        add_res = adb_addResponse_create(env);
        adb_addResponse_set_addReturn(add_res, env, ret_val);
        return add_res;
    }
    

    工作人员实现计算器服务加法操作的方式:

    int CalculatorImpl::add(int param_1, int param_2)
    {
      return param_1 + param_2;
    }
    

    关于代码生成和编译过程如下:

    对于 Axis2/C:

    # generate service from WSDL
    WSDL2C.sh -uri Calculator.wsdl -u -ss -sd
    # implement src/axis2_skel_Calculator.c
    # compile and install
    cd src
    # build
    sh build.sh
    # install
    sudo mkdir $AXIS2C_HOME/services/calculator
    sudo cp lib*.so ../resources/*.xml $AXIS2C_HOME/services/calculator
    

    对于 WSF 工作人员:

    # generate service from WSDL
    staff_codegen -pwsdl -tcomponent_all Calculator.wsdl
    # implement src/CalculatorImpl.cpp
    # build and install
    make && sudo -E make install
    

    当然,您可以在 Axis2/C-非官方上使用 WSF Staff 来获得两者的所有好处。

    【讨论】:

    • 感谢您的出色回答。您是否也熟悉 C(或 C++)的 WSO2 Web 服务框架?这些也基于 Axis2/C。它们是否包含内存泄漏?我真的不介意需要编写的代码量。我最关心的是可靠性。
    • WSO2 for C 只是一个 Axis2/C 加上像 Sandesha、Rampart 这样的附加模块...它确实具有与原始 Axis2/C 相同的内存泄漏以及由 Sandesha2/C 引入的额外泄漏。 WSO2/C++是在WSO2/C的基础上,在C接口的基础上增加了C++接口。如果你想避免内存泄漏,你可以使用普通的 Axis2/C-unofficial without ADB,或者 Axis/C-unofficial + WSF Staff - 它有自己的数据绑定模型并且没有任何已知的内存泄漏。如果您不介意需要编写的代码量,您可能应该选择 Axis2/C-unofficial without ADB
    【解决方案2】:

    今天我在谷歌搜索时发现了 Axis2c-unofficial,我需要检查一下。

    至于 Axis2c(WSO2 版本),我目前在我的移动应用程序(基于 Qt - Meego/BB10)中使用它,您可能不想自己编写代码,而是从 WSDL 文件生成它。就像 loentar 所说的那样,WSO2 版本实际上只是 Axis2c 的一个包装器,但它确实使它更容易设置。我想说使用 WSO2 版本或使用非官方版本,我发现 Axis2c 编译起来很棘手(我是 C/C++/Qt/SOAP 的新手,我试图为 Meego/BB10 交叉编译它 - 你可以想象这是怎么回事!),还要记住 STAFF 是基于 Qt 的包装器,所以这是另一个依赖项。

    底线是使用代码生成器,但要注意:

    1 - 代码生成器有一个“xml 节点的其余部分”(不记得方法/名称的名称),但基本上所有无法映射的 xml 都进入该节点,您可以针对该节点运行 xpath 查询.然而,有时这个节点会被放在实际的真实节点对象之前,所以 xml 只是被转储到这个节点而不是你真正想要的节点对象。

    2 - 生成的代码很大 - 我的意思是真的很大!我的移动库大约 190mb 和大约 40mb 没有调试。

    3 - 代码生成器是 java,因此您也可以使用 eclipse 让代码生成您的代码获取器!

    第三点非常重要,我个人认为这意味着我需要编写更少的代码,因为 XML 中的每个项目都映射到一个字符串,并且从我的 QML 代码(GUI 代码)中我只需处理这个字符串。

    我可能跑题了 - 虽然我宁愿使用 Java 来生成代码(更好的支持),但如果可以选择的话,希望这会有所帮助。

    对杰夫的回应:

    在尝试为 BB10 编译 WSO2 时,我意识到 WSO2 仅包含 Axis2c 文件夹,它首先编译各种 asix2c 库(我认为它首先编译),然后是 WSO2 库(sandesh、savan 等.),我很幸运,我真正想要的只是 WSDL 的 XML 序列化/反序列化,而不是任何高级的 soap 功能(除了最基本的之外,我当然对 soap 了解不多)。

    假设头文件/api 完全相同,可以简单地用非官方库替换axis2c 库。或者甚至只是将非官方文件夹放在官方文件夹上。

    我自己必须先在eclipse中编译二进制文件(BB10 SDK),这是一项漫长而艰巨的任务,但与Nokias Meego SDK不同,BB10没有交叉编译工具,在Meego中非常简单,我必须为零变化。

    【讨论】:

    • 现在我认为 WSO2 版本是最容易使用的方法,但他们使用的 Axis2C 版本中可能存在内存泄漏是一个已知问题。我想知道将 WSO2 包装器与非官方的 Axis2C 结合起来需要做多少工作,应该最大限度地减少内存泄漏。
    猜你喜欢
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 2011-12-16
    • 2012-02-25
    相关资源
    最近更新 更多