杰瑞科技汇

C如何调用Java的WebService接口?

由于C语言本身没有内置的HTTP/XML/JSON处理能力,我们需要借助第三方库来完成这项工作,根据WebService的类型(主要是SOAP和RESTful),推荐的方案有所不同。

C如何调用Java的WebService接口?-图1

下面我将分两种最常见的情况详细讲解:

  1. 调用SOAP WebService (较传统,基于XML)
  2. 调用RESTful WebService (更现代,通常基于JSON)

调用 SOAP WebService

SOAP (Simple Object Access Protocol) 是一种基于XML的协议,它定义了一套严格的消息格式,在Java世界,开发SOAP服务通常使用JAX-WS (Java API for XML Web Services) 框架。

在C语言端,最常用和最强大的库是 gSOAP

gSOAP 方案简介

gSOAP是一个用于开发C/C++语言的SOAP/XML Web服务的工具包和运行库,它可以将WSDL (Web Services Description Language) 文件自动转换为C/C++的客户端存根代码,这些存根代码封装了底层的网络通信和XML解析细节,让你可以像调用本地函数一样调用远程的WebService方法。

详细步骤

准备工作:获取Java WebService的WSDL文件

你的Java WebService必须提供一个WSDL文件,这是C客户端生成代码的蓝图。

你可以在WebService的URL后面加上 ?wsdl 来获取,如果你的服务地址是 http://localhost:8080/MyService,那么WSDL地址就是 http://localhost:8080/MyService?wsdl

C如何调用Java的WebService接口?-图2

安装 gSOAP工具包

gSOAP官网 下载工具包,它是一个ZIP压缩包,解压即可使用。

使用 wsdl2h 生成C/C++头文件

打开命令行,进入gSOAP的 bin/win64 (或对应你系统的目录) 目录,执行以下命令:

# wsdl2h -o output.h -k -s -t myTypeMap.dat http://your-java-service-url?wsdl
  • -o output.h: 指定输出的头文件名。
  • -k: 保持与WSDL中相同的元素顺序。
  • -s: 生成STL风格的代码。
  • -t myTypeMap.dat: 指定一个类型映射文件,用于处理WSDL中可能无法自动映射的复杂数据类型(例如Java的ListMap)。
  • WSDL文件的URL。

重要提示:如果Java WebService中使用了复杂类型(如自定义对象、List等),wsdl2h 可能无法完美生成对应的C结构体,这时你需要手动编辑 myTypeMap.dat 文件来定义这些类型,然后再运行 wsdl2h

使用 soapcpp2 生成客户端存根代码

使用上一步生成的头文件,运行 soapcpp2 来生成客户端所需的全部代码。

# soapcpp2 -j -C -I"path/to/gsoap/import" output.h
  • -j: 生成与gSOAP的stdsoap2.h兼容的代码。
  • -C: 只生成客户端代码。
  • -I: 指定gSOAP的import目录,这是必须的,因为里面包含了标准类型定义。

执行后,你会得到一堆文件,最重要的是:

  • soapC.c: 序列化/反序列化函数的实现。
  • soapClient.c: 客户端存根的实现。
  • soapH.h: 客户端需要包含的函数声明。
  • .nsmap: 命名空间映射文件。

编写C客户端代码并调用

你可以编写一个C程序来调用WebService了。

C如何调用Java的WebService接口?-图3

假设你的Java Service有一个方法 add(int a, int b),返回 int

client.c 示例代码:

#include "soapH.h"       // 包含由soapcpp2生成的函数声明
#include "myservice.nsmap" // 包含命名空间映射
int main(int argc, char **argv) {
    struct soap soap; // 创建一个SOAP运行时环境
    soap_init(&soap); // 初始化SOAP环境
    // 设置目标服务的URL (WSDL中的地址)
    const char *soap_endpoint = "http://localhost:8080/MyService";
    // 定义输入参数
    int a = 5;
    int b = 10;
    int result;
    // --- 调用WebService ---
    // 函数名通常是WSDL中操作名 + "Response"
    // 参数顺序: soap环境, 输出参数指针, 输入参数1, 输入参数2, ...
    // 最后一个参数是服务的URL
    if (soap_call___ns1__add(&soap, soap_endpoint, NULL, &a, &b, &result) == SOAP_OK) {
        // 调用成功
        printf("调用成功!\n");
        printf("结果: %d + %d = %d\n", a, b, result);
    } else {
        // 调用失败
        soap_print_fault(&soap, stderr); // 打印详细的错误信息
    }
    soap_end(&soap); // 清理SOAP环境
    soap_destroy(&soap); // 释放动态数据
    return 0;
}

编译和链接

你需要编译你的C代码,并链接gSOAP的库文件和生成的代码。

# Linux/macOS (使用gcc)
gcc -o myclient client.c soapC.c stdsoap2.c -lgsoap -lpthread -ldl
# Windows (使用Visual Studio或MinGW)
# cl myclient.cpp soapC.cpp stdsoap2.cpp /I"path/to/gsoap/include" /link /LIBPATH:"path/to/gsoap/lib" gsoap.lib ws2_32.lib

调用 RESTful WebService

RESTful WebService通常通过HTTP协议,以JSON或XML格式交换数据,在C语言中调用它,本质就是发送一个HTTP请求并解析返回的JSON响应。

最常用的库是 libcurl (用于HTTP请求) 和 cJSON (用于JSON解析)。

详细步骤

安装依赖库

  • libcurl: 用于处理所有HTTP/HTTPS请求。
    • Ubuntu/Debian: sudo apt-get install libcurl4-openssl-dev
    • CentOS/RHEL: sudo yum install libcurl-devel
    • Windows: 从 curl官网 下载预编译库或自行编译。
  • cJSON: 用于解析和生成JSON数据。
    • Ubuntu/Debian: sudo apt-get install libcjson-dev
    • CentOS/RHEL: sudo yum install libcjson-devel
    • Windows: 从 cJSON官网 下载源码,编译成静态库或动态库。

编写C客户端代码

假设你的Java RESTful Service有一个POST接口 /api/user,接收一个JSON对象 {"name": "John", "age": 30},并返回一个包含ID的JSON对象 {"id": 123, "status": "success"}

rest_client.c 示例代码:

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <cJSON.h>
// 用于存储HTTP响应数据的结构体
struct MemoryStruct {
    char *memory;
    size_t size;
};
// 回调函数,libcurl会将在内存中接收到的数据块追加到MemoryStruct中
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    char *ptr = realloc(mem->memory, mem->size + realsize + 1);
    if (!ptr) {
        /* out of memory! */
        printf("not enough memory (realloc returned NULL)\n");
        return 0;
    }
    mem->memory = ptr;
    memcpy(&(mem->memory[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;
    return realsize;
}
int main(void) {
    CURL *curl;
    CURLcode res;
    // 1. 初始化libcurl
    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();
    if (curl) {
        // 2. 准备要发送的JSON数据
        cJSON *json_payload = cJSON_CreateObject();
        cJSON_AddStringToObject(json_payload, "name", "John");
        cJSON_AddNumberToObject(json_payload, "age", 30);
        char *json_string = cJSON_Print(json_payload); // 将JSON对象转为字符串
        printf("发送的JSON

分享:
扫描分享到社交APP
上一篇
下一篇