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

下面我将分两种最常见的情况详细讲解:
- 调用SOAP WebService (较传统,基于XML)
- 调用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。

安装 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的List或Map)。- 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了。

假设你的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官网 下载预编译库或自行编译。
- Ubuntu/Debian:
- cJSON: 用于解析和生成JSON数据。
- Ubuntu/Debian:
sudo apt-get install libcjson-dev - CentOS/RHEL:
sudo yum install libcjson-devel - Windows: 从 cJSON官网 下载源码,编译成静态库或动态库。
- Ubuntu/Debian:
编写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
