C 语言 WebService 教程 (使用 gSOAP)
目录
- 什么是 WebService?
- 为什么用 C 语言做 WebService?
- 什么是 gSOAP?
- 环境准备
- 创建一个简单的 WebService (服务器端)
- 步骤 1: 定义服务接口 (.h 文件)
- 步骤 2: 使用 gSOAP 工具生成代码
- 步骤 3: 实现业务逻辑 (server.c)
- 步骤 4: 编译并运行服务器
- 调用 WebService (客户端)
- 步骤 1: 使用相同的接口文件生成客户端代码
- 步骤 2: 编写客户端调用代码 (client.c)
- 步骤 3: 编译并运行客户端
- 高级概念
- 处理复杂数据类型 (结构体、数组)
- 处理文件传输
- 总结与资源
什么是 WebService?
WebService 是一种基于 Web 的、跨平台的、跨语言的、自描述的、可交互的分布式应用程序组件,它使用 XML (eXtensible Markup Language) 来进行数据交换,并通过 SOAP (Simple Object Access Protocol) 协议在网络上传输数据。

WebService 就是一个可以通过网络调用的“函数”,这个函数运行在另一台机器上,你的程序可以向它发送请求,并获取返回结果,而不需要关心它内部是如何实现的,以及它使用的是什么编程语言。
为什么用 C 语言做 WebService?
虽然 Java, C#, Python 等语言在 WebService 开发中更为流行,但在某些特定领域,C 语言依然是首选:
- 嵌入式系统与物联网: 许多嵌入式设备(如路由器、摄像头、工业控制器)资源有限,运行的是 C 语言,通过 WebService 可以让这些设备提供标准化的网络接口,方便远程管理和控制。
- 高性能计算: C 语言以其接近硬件的高效性著称,对于计算密集型的后端服务,用 C 语言实现 WebService 可以获得极致的性能。
- 遗留系统集成: 大量核心业务系统是用 C/C++ 编写的,通过 WebService 可以将这些旧系统包装成现代化的服务,供其他语言的应用调用。
- 底层库封装: 将一些强大的 C 语言库(如图像处理、科学计算库)通过 WebService 的形式暴露出来,方便其他语言调用。
什么是 gSOAP?
直接用 C 语言手动处理 XML 和 SOAP 协议是一项非常繁琐且容易出错的工作。gSOAP 是一个开源的 C/C++ 工具包,它自动化了这一切。
它的核心思想是:

- 你只需要用 C/C++ 定义你的函数接口(通常在一个
.h文件中)。 - gSOAP 工具会自动将这个接口文件转换成:
- 服务器端代码: 包含了处理 HTTP 请求、解析 SOAP、调用你的 C 函数、封装 SOAP 响应等所有 boilerplate(样板)代码。
- 客户端代码: 包含了构建 SOAP 请求、发送 HTTP 请求、解析 SOAP 响应等代码。
你只需要专注于实现你的核心业务逻辑即可。
环境准备
-
操作系统: Windows, Linux, macOS 均可,本教程以 Linux (Ubuntu/Debian) 为例。
-
C/C++ 编译器: GCC/G++
-
gSOAP 工具包:
(图片来源网络,侵删)- 访问 gSOAP 官网 下载最新版本的源码包。
- 解压并编译安装 gSOAP,这会生成
wsdl2h和soapcpp2两个核心工具。
# 下载并解压 (假设版本为 2.8.112) tar -xvzf gsoap_2.8.112.tar.gz cd gsoap-2.8/gsoap/ ./configure make sudo make install
确保这两个工具在您的
PATH环境变量中,可以通过which wsdl2h和which soapcpp2来检查。
实战一:创建一个简单的 WebService (服务器端)
我们的目标是创建一个 WebService,它提供一个 Add 函数,接收两个整数,返回它们的和。
步骤 1: 定义服务接口 (calc.h)
创建一个名为 calc.h 的头文件,用 C 语言的函数原型来定义你的服务,gSOAP 会根据这个文件生成代码。
calc.h
// calc.h int Add(int a, int b);
就这么简单!gSOAP 会自动为这些函数参数和返回值生成 XML Schema 定义。
步骤 2: 使用 gSOAP 工具生成代码
在终端中,使用 soapcpp2 工具处理你的 .h 文件。
# -C 表示只生成服务器端代码 # -x 表示生成示例代码 soapcpp2 -C -x calc.h
执行后,你会看到生成了很多新文件:
calc.nsmap: SOAP 命名空间映射文件。calcSoapBinding.nsmap: 绑定相关的命名空间文件。calcServer.c: 服务器端的 C 代码框架。calcServer.cpp: 服务器端的 C++ 代码框架。calcH.h: 生成的头文件,包含了所有 gSOAP 需要的函数声明。calcStub.h: 生成的存根文件,用于客户端。calc.c和calc.cpp: 你需要在这里实现你的业务逻辑。
步骤 3: 实现业务逻辑 (server.c)
打开 calc.c 文件,你会看到一个空的函数体,在里面填入你的具体实现。
calc.c
// calc.c
#include "calcH.h" // 必须包含生成的头文件
#include "calc.nsmap" // 必须包含命名空间映射文件
// 实现 Add 函数
int Add(int a, int b)
{
printf("Server: Add function called with a=%d, b=%d\n", a, b);
return a + b;
}
// gSOAP 需要一个 main 函数来启动服务
int main()
{
// 初始化 gSOAP 运行时环境
struct soap soap;
soap_init(&soap);
// 绑定服务到端口 8080
// 第三个参数是日志文件,NULL 表示不记录
// 第四个参数是命名空间映射文件
if (soap_bind(&soap, NULL, 8080, 100) < 0)
{
soap_print_fault(&soap, stderr);
exit(1);
}
printf("Server: Socket connection successful. Waiting for clients...\n");
// 循环等待并处理客户端连接
for (;;)
{
struct soap *tsoap;
// 接受一个客户端连接
if ((tsoap = soap_accept(&soap)) < 0)
{
if (soap.errnum != 2) // 2 是超时错误,可以忽略
{
soap_print_fault(&soap, stderr);
}
break;
}
// 打印连接的客户端信息
fprintf(stderr, "Client connected from IP %s, port %d\n", tsoap->ip, tsoap->port);
// 处理请求
if (soap_serve(tsoap) < 0)
{
soap_print_fault(tsoap, stderr);
}
// 关闭连接
soap_end(tsoap);
soap_free(tsoap);
}
soap_done(&soap);
return 0;
}
步骤 4: 编译并运行服务器
你需要链接 gSOAP 的库和必要的库(如 ssl, crypto)。
# 编译服务器 gcc -o server server.c calc.c -lgsoap++ # 运行服务器 (需要 root 权限绑定 1024 以下的端口) sudo ./server
如果一切顺利,你会看到:
Server: Socket connection successful. Waiting for clients...
你的 C 语言 WebService 服务器已经启动,并监听在 8080 端口上!
实战二:调用 WebService (客户端)
现在我们创建一个客户端来调用刚刚部署的 Add 服务。
步骤 1: 使用相同的接口文件生成客户端代码
我们再次使用 soapcpp2,但这次使用 -c 参数来生成客户端代码。
# -c 表示只生成客户端代码 # -x 表示生成示例代码 soapcpp2 -c -x calc.h
这会生成 calcClient.c, calcClient.cpp 等客户端相关的文件。
步骤 2: 编写客户端调用代码 (client.c)
创建一个 client.c 文件,使用 gSOAP 生成的存根函数来调用服务。
client.c
// client.c
#include "calcStub.h" // 必须包含客户端存根头文件
#include "calc.nsmap" // 必须包含命名空间映射文件
int main()
{
struct soap soap;
int result;
// 初始化 gSOAP 运行时环境
soap_init(&soap);
// 设置要调用的服务端 URL
soap_endpoint = "http://localhost:8080"; // 服务器地址和端口
// 调用远程的 Add 函数
// 参数: soap环境, 参数1, 参数2, 返回值指针
if (soap_call_Add(&soap, NULL, NULL, 10, 20, &result) == SOAP_OK)
{
printf("Client: Add(10, 20) = %d\n", result);
}
else
{
// 如果调用失败,打印错误信息
soap_print_fault(&soap, stderr);
}
// 清理 gSOAP 运行时环境
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
return 0;
}
步骤 3: 编译并运行客户端
# 编译客户端 gcc -o client client.c -lgsoap++ # 运行客户端 (确保服务器正在运行) ./client
预期输出:
在客户端终端:
Client: Add(10, 20) = 30
在服务器终端:
Server: Add function called with a=10, b=20
恭喜!你已经成功地在 C 语言中创建并调用了一个 WebService!
高级概念
处理复杂数据类型 (结构体、数组)
gSOAP 的强大之处在于它能很好地处理复杂数据。
-
修改
calc.h:// calc.h struct MyStruct { int id; char name[50]; }; // 返回一个结构体 struct MyStruct GetInfo(int id); // 接收一个结构体数组 int ProcessData(struct MyStruct data[], int size); -
重新生成代码:
soapcpp2 -C -x calc.h # 服务器 soapcpp2 -c -x calc.h # 客户端
-
实现和调用: 在
calc.c中实现GetInfo和ProcessData。 在客户端,你可以直接使用struct MyStruct类型和数组,gSOAP 会自动完成序列化和反序列化。
处理文件传输
要传输文件,通常使用 xsd 数据类型,如 base64Binary。
-
修改
calc.h:// calc.h #include <stdint.h> // base64Binary 类型在 gSOAP 中通常用 unsigned char* 和 size_t 表示 int UploadFile(const char* filename, unsigned char** file_data, size_t* file_size);
-
重新生成代码并实现: 在服务器端
UploadFile实现中,你需要将文件内容读入内存,然后通过file_data和file_size返回给 gSOAP,客户端则会接收到这些数据并可以写入文件。
总结与资源
-
核心要点:
- gSOAP 是 C 语言 WebService 开发的利器,它将复杂的 XML/SOAP 处理封装起来。
- 开发流程:定义接口 (
.h) ->soapcpp2生成代码 -> 实现业务逻辑 -> 编译链接。 - 服务器端专注于
soap_bind,soap_accept,soap_serve。 - 客户端专注于调用
soap_call_*系列函数。
-
资源:
- gSOAP 官方文档: http://www.cs.fsu.edu/~engelen/soapdocs.html (最权威的资料,虽然有些陈旧,但内容详实)
- gSOAP 源码和下载: http://www.genivia.com/products.html
- 在线 WSDL 工具: 可以用来测试你的 WebService,SoapUI。
希望这份教程能帮助你顺利入门 C 语言的 WebService 开发!
