XmlRPC入门_基于组合类型的客户端、服务端

发布时间 2023-12-01 16:41:20作者: 左边的翼

1、客户端

#include <stdlib.h>
#include <stdio.h>

#include <xmlrpc-c/base.h>
#include <xmlrpc-c/client.h>

#include "config.h"  /* information about this build environment */

#define NAME "Xmlrpc-c Test Client"
#define VERSION "1.0"

static void
dieIfFaultOccurred (xmlrpc_env * const envP) {
    if (envP->fault_occurred) {
        fprintf(stderr, "ERROR: %s (%d)\n",
                envP->fault_string, envP->fault_code);
        exit(1);
    }
}



struct ratio {
    double dividend;
    double divisor;
};



int
main(int           const argc,
     const char ** const argv) {

    const char * const serverUrl = "http://localhost:8080/RPC2";
    const char * const methodName = "example.divide";
    unsigned int const argVersion = 1;
    struct ratio const data[] = {{1,2},{12,3},{10,3},{89,3000}};
    xmlrpc_env env;
    xmlrpc_value * resultP;
    unsigned int i;
    xmlrpc_value * ratioArrayP;
    unsigned int quotientCt;

    if (argc-1 > 0) {
        fprintf(stderr, "This program has no arguments\n");
        exit(1);
    }

    xmlrpc_env_init(&env);

    xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
    dieIfFaultOccurred(&env);

    /* Build the 2nd method argument: the array of ratios */

    ratioArrayP = xmlrpc_array_new(&env);
    dieIfFaultOccurred(&env);

    for (i = 0; i < 4; ++i) {
        xmlrpc_value * dividendP;
        xmlrpc_value * divisorP;
        xmlrpc_value * ratioP;

        dividendP = xmlrpc_double_new(&env, data[i].dividend);
        dieIfFaultOccurred(&env);
        divisorP  = xmlrpc_double_new(&env, data[i].divisor);
        dieIfFaultOccurred(&env);

        ratioP = xmlrpc_struct_new(&env);
        dieIfFaultOccurred(&env);

        xmlrpc_struct_set_value(&env, ratioP, "DIVIDEND", dividendP);
        dieIfFaultOccurred(&env);
        xmlrpc_struct_set_value(&env, ratioP, "DIVISOR",  divisorP);
        dieIfFaultOccurred(&env);

        xmlrpc_array_append_item(&env, ratioArrayP, ratioP);
        dieIfFaultOccurred(&env);

        xmlrpc_DECREF(ratioP);
        xmlrpc_DECREF(divisorP);
        xmlrpc_DECREF(dividendP);
    }

    /* Make the call */

    resultP = xmlrpc_client_call(&env, serverUrl, methodName, "(iA)",
                                 (xmlrpc_int32) argVersion, ratioArrayP);
    dieIfFaultOccurred(&env);

    /* Print out the quotients returned */

    quotientCt = xmlrpc_array_size(&env, resultP);
    dieIfFaultOccurred(&env);

    for (i = 0; i < quotientCt; ++i) {
        xmlrpc_value * quotientP;
        xmlrpc_double quotient;

        xmlrpc_array_read_item(&env, resultP, i, &quotientP);
        dieIfFaultOccurred(&env);

        xmlrpc_read_double(&env, quotientP, &quotient);
        dieIfFaultOccurred(&env);

        printf("Server says quotient %u is %f\n", i, quotient);

        xmlrpc_DECREF(quotientP);
    }

    xmlrpc_DECREF(resultP);

    xmlrpc_env_clean(&env);

    xmlrpc_client_cleanup();

    return 0;
}

2、服务端

#define WIN32_LEAN_AND_MEAN  /* required by xmlrpc-c/server_abyss.h */

#include <stdlib.h>
#include <stdio.h>

#include <xmlrpc-c/base.h>
#include <xmlrpc-c/server.h>
#include <xmlrpc-c/server_abyss.h>

#include "config.h"  /* information about this build environment */



static void
computeQuotient(xmlrpc_env *    const envP,
                xmlrpc_value *  const ratioP,
                xmlrpc_double * const quotientP) {

    xmlrpc_value * dividendP;

    xmlrpc_struct_find_value(envP, ratioP, "DIVIDEND", &dividendP);

    if (!envP->fault_occurred) {
        if (!dividendP)
            xmlrpc_env_set_fault(
                envP, 0, "Structure is missing 'DIVIDEND' member");
        else {
            xmlrpc_value * divisorP;

            xmlrpc_struct_find_value(envP, ratioP, "DIVISOR", &divisorP);

            if (!envP->fault_occurred) {
                if (!divisorP)
                    xmlrpc_env_set_fault(
                        envP, 0, "Structure is missing 'DIVISOR' member");
                else {
                    xmlrpc_double dividend;

                    xmlrpc_read_double(envP, dividendP, &dividend);

                    if (!envP->fault_occurred) {
                        xmlrpc_double divisor;

                        xmlrpc_read_double(envP, divisorP, &divisor);

                        if (!envP->fault_occurred)
                            *quotientP = dividend / divisor;
                    }
                    xmlrpc_DECREF(divisorP);
                }
            }
            xmlrpc_DECREF(dividendP);
        }
    }
}



static void
computeQuotients(xmlrpc_env *    const envP,
                 xmlrpc_value *  const ratioArrayP,
                 xmlrpc_value ** const quotientArrayPP) {

    xmlrpc_value * quotientArrayP;

    quotientArrayP = xmlrpc_array_new(envP);
    if (!envP->fault_occurred) {

        unsigned int const ratioCt = xmlrpc_array_size(envP, ratioArrayP);

        unsigned int i;

        for (i = 0; i < ratioCt && !envP->fault_occurred; ++i) {
            xmlrpc_value * ratioP;

            xmlrpc_array_read_item(envP, ratioArrayP, i, &ratioP);

            if (!envP->fault_occurred) {
                xmlrpc_double quotient;

                computeQuotient(envP, ratioP, &quotient);

                if (!envP->fault_occurred) {
                    xmlrpc_value * quotientP;

                    quotientP = xmlrpc_double_new(envP, quotient);

                    if (!envP->fault_occurred) {
                        xmlrpc_array_append_item(envP, quotientArrayP,
                                                 quotientP);

                        xmlrpc_DECREF(quotientP);
                    }
                }
                xmlrpc_DECREF(ratioP);
            }
        }
        if (envP->fault_occurred)
            xmlrpc_DECREF(quotientArrayP);
        else
            *quotientArrayPP = quotientArrayP;
    }
}



static xmlrpc_value *
example_divide(xmlrpc_env *   const envP,
               xmlrpc_value * const paramArrayP,
               void *         const serverInfo,
               void *         const channelInfo) {

    xmlrpc_value * retvalP;
    xmlrpc_int32 argVersion;
    xmlrpc_value * ratioArrayP;

    xmlrpc_decompose_value(envP, paramArrayP, "(iA)",
                           &argVersion, &ratioArrayP);
    if (envP->fault_occurred)
        return NULL;

    if (argVersion != 1) {
        xmlrpc_env_set_fault(envP, 0, "Parameter list version must be 1");
        return NULL;
    }

    computeQuotients(envP, ratioArrayP, &retvalP);

    xmlrpc_DECREF(ratioArrayP);

    if (envP->fault_occurred)
        return NULL;

    return retvalP;
}



int
main(int           const argc,
     const char ** const argv) {

    struct xmlrpc_method_info3 const methodInfo = {
        /* .methodName     = */ "example.divide",
        /* .methodFunction = */ &example_divide,
    };
    xmlrpc_server_abyss_parms serverparm;
    xmlrpc_registry * registryP;
    xmlrpc_env env;

    if (argc-1 != 1) {
        fprintf(stderr, "You must specify 1 argument:  The TCP port "
                "number on which the server will accept connections "
                "for RPCs (8080 is a common choice).  "
                "You specified %d arguments.\n",  argc-1);
        exit(1);
    }

    xmlrpc_env_init(&env);

    registryP = xmlrpc_registry_new(&env);

    xmlrpc_registry_add_method3(&env, registryP, &methodInfo);

    /* In the modern form of the Abyss API, we supply parameters in memory
       like a normal API.  We select the modern form by setting
       config_file_name to NULL:
    */
    serverparm.config_file_name = NULL;
    serverparm.registryP        = registryP;
    serverparm.port_number      = atoi(argv[1]);
    serverparm.log_file_name    = "/tmp/xmlrpc_log";

    printf("Running XML-RPC server...\n");

    xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name));

    /* xmlrpc_server_abyss() never returns */

    return 0;
}