libcurl + libxml2 + soapUI开发SOAP客户端程序

2010年,我写过一些使用gSOAP开发SOAP应用程序的系列文章,共8篇,详情请参考以前的博文:

(1) 股票信息客户端程序

(2) 股票信息服务端程序

(3) iconv解决中文乱码问题

(4) iconv解决中文乱码问题(续)

(5) libxml2解析SOAP响应消息

(6) 在HP-UX下编译gSOAP-2.7.17

(7) 基于HTTPS的基本认证(Basic Authentication)

(8) 自定义header实现用户名令牌认证(Usernametoken Authentication)


使用gSOAP,基本上可以实现傻瓜相机式的快速开发。不过,大部分操作系统,即使是Linux,都没有自带gSOAP,要使用它就必须首先下载、编译、安装。另外,虽然gSOAP本身是跨平台的,但是它必须基于一系列GNU的组件,如果不满足条件的话,恭喜你啦,可以看看我在HP-UX下使用gSOAP有多么的麻烦。再次,gSOAP封装得太多,使用起来太简单,可能也不能满足部分人士(比如我这种人啦)学习的需要。

那么,Linux下有没有免安装的、更容易实现跨平台的、比gSOAP轻量级的、能够进一步学习和理解HTTP、SOAP的开发工具呢?

答案是肯定的。curl就是RHEL Linux自带的、功能强大的客户端工具,它支持许多协议:HTTP、FTP、TELNET、SMTP、POP3等等,基于HTTP和HTTPS的SOAP更是不在话下了。更妙的是,它同时还提供一套编程接口libcurl,可以把curl命令的各项功能嵌入到你自己的C程序中。所以,除了SOAP客户端,使用libcurl,还可以开发出下载工具和邮件客户端,这是gSOAP无法相比的。

由于SOAP和XML的天然联系,最好使用同样是Linux自带的libxml2来生成SOAP请求和解析SOAP响应。即使有的Unix系统、甚至Windows系统,没有libcurl或者libxml2,下载源代码编译安装基本上也不会遇到什么麻烦,比编译gSOAP的过程轻松多了。Windows下编译libxml2的过程及可能遇到的问题,请参考以前的博文:http://blog.csdn.net/yui/archive/2011/01/02/6112622.aspx

此外,我们还需要soapUI进行辅助开发,我觉得soapUI最实用的功能是能够测试一个SOAP连接是否成功,并且一字不漏地呈现它的请求格式,包括其HTTP头信息。这样,我们就可以根据一个在soapUI里测试成功的范例,依样画葫芦,使用libcurl把它重现出来。soapUI的官方网站是:http://www.soapui.org/

那么,libcurl+libxml2是否就可以取代gSOAP呢?当然也不是,首先,libcurl只是一个客户端工具,开发不了服务端程序,其次,使用libxml2生成SOAP请求和解析SOAP响应,在大部分场合都比调用gSOAP的接口麻烦,这个也是必须承认的事实。仅仅进行SOAP客户端开发的话,如果是在GNU Linux下,还是推荐gSOAP。libcurl+libxml2方案的亮点是:支持多种协议、有利于跨平台。总之,多备一把刀,总是好的,免得杀鸡的时候被迫用了把牛刀,砍树的时候又被迫用了把小刀。

以下是基于HTTP的SOAP客户端程序的例子,用了http://www.webxml.com.cn/zh_cn/web_services.aspx 提供的Web Service,应该很容易看懂。中文乱码的问题就不在这里多说了,上面gSOAP的系列文章有解释。

#include <stdio.h> #include <string.h> #include <curl/curl.h> #include <libxml/parser.h> #include <libxml/xmlmemory.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> static void set_value(xmlXPathContextPtr context, const xmlChar *xpath, const xmlChar *value){ xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context); if ( result ) { xmlNodeSetPtr nodeset = result->nodesetval; xmlNodeSetContent(nodeset->nodeTab[0], value); xmlXPathFreeObject(result); } } static void get_request(char *buffer, int *len, const char *stock_code) { xmlChar *buff; xmlDocPtr doc = xmlParseFile("stock.xml"); if ( doc == NULL ) { printf("xmlParseFile failed\n"); return; } xmlXPathContextPtr context = xmlXPathNewContext(doc); if ( context == NULL ) { printf("xmlXPathNewContext failed\n"); return; } xmlXPathRegisterNs(context, (const xmlChar *)"soapenv", (const xmlChar *)"http://schemas.xmlsoap.org/soap/envelope/"); xmlXPathRegisterNs(context, (const xmlChar *)"web", (const xmlChar *)"http://WebXml.com.cn/"); set_value(context, (const xmlChar *)"//web:theStockCode", (const xmlChar *) stock_code); xmlDocDumpMemory(doc, &buff, len); strcpy(buffer, (char *) buff); printf("%s\n", buffer); xmlFree(buff); xmlXPathFreeContext(context); xmlFreeDoc(doc); xmlCleanupParser(); } int main(int argc, char **argv) { const char *stock_code = argv[1]; char buffer[2048]; int len = 0; get_request(buffer, &len, stock_code); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: text/xml;charset=UTF-8"); headers = curl_slist_append(headers, "SOAPAction: \"http://WebXml.com.cn/getStockInfoByCode\""); CURL *curl = curl_easy_init(); if ( curl ) { curl_easy_setopt(curl, CURLOPT_URL, "http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buffer); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(buffer)); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_HEADER, 1); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_perform(curl); /* always cleanup */ curl_easy_cleanup(curl); curl_slist_free_all(headers); } return 0; }

程序需要读取stock.xml作为SOAP请求模板,也就是从soapUI测试过程中抓取的内容:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://WebXml.com.cn/"> <soapenv:Header/> <soapenv:Body> <web:getStockInfoByCode> <!--Optional:--> <web:theStockCode>?</web:theStockCode> </web:getStockInfoByCode> </soapenv:Body> </soapenv:Envelope>

如果需要开发基于HTTPS的SOAP客户端的话,首先要在libcurl添加openssl支持,我的前一篇博文也有介绍:http://blog.csdn.net/yui/archive/2011/01/31/6170889.aspx

使用的方法基本与前面的程序一样,不过可能需要多加一句:


curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);

另外,如果在Code::Blocks下,编译的关键是库文件链接次序,请见上一篇博文最后的图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值