免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1622 | 回复: 0
打印 上一主题 下一主题

使用gSOAP开发实例(3) iconv解决中文乱码问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-21 08:44 |只看该作者 |倒序浏览

电信provisioning系统中,常常需要与远程服务器实时交换一些数据,以完成用户的请求。由于简单对象访问协议(Simple Object Access Protocol, SOAP)的流行,许多涉及到第三方的应用,我们一般都比较乐意使用SOAP来开发。不过,由于可能涉及到公司的机密,本系列教程的开发实例尽量采用在网上已经公开的Web Service资源。

 

我开发SOAP应用程序已经有一定的经验,在C/C++环境下一般使用gSOAP,而在Java环境下一般采用axis2。比较两者的话,除了开发语言之外,还是有不少差别,处理中文字符就是其中之一。网上分别搜索一下“axis2 乱码“gSOAP 乱码,匹配的结果是相差很远的。Axis2好像比较智能,能够识别服务端的字符编码,这方面的问题也少,而最新版本的gSOAP,很可能还是需要程序员做多很多功夫。

 

在第一节客户端的教程中,输出的中文股票名称,其实就是乱码,不过为了主次之分,当时做了特别处理,忽略过去。

 

网上解决gSOAP乱码的主流方案是,初始化soap对象之后对其设置SOAP_C_UTFSTRING参数,例如:

        struct soap soap;

        soap_init(&soap);

        soap_set_mode(&soap, SOAP_C_UTFSTRING);

 

但是,单纯这样修改,在某些特定设置的机器上可能有效,反正我试过,仍然是乱码,如下图。怎么办呢?

 

 

Linux下有一个字符编码转换的工具iconv,同时也提供了一套可编程的接口。利用它,就可以测试出来自于服务端中文字符编码的类型,从而进一步实现在程序中自动转换编码。

 

Iconv常用用法是:iconv -t=to_charset -f=from_charset filename

因此,把需要转换编码的内容保存为一个文件,然后执行iconv试出需要转换的编码类型。from­_charset几乎百分百肯定就是utf8,那么to_charset来来去去就那么几个,一个个试也很快试出来了。最终得出的结果是gbk编码,从而修改客户端程序以解决乱码问题。

  1. #include <iconv.h>  
  2.   
  3. #include "soapH.h"  
  4. #include "ChinaStockWebServiceSoap12.nsmap"  
  5.   
  6. #define OUTPUT_LEN 32  
  7.   
  8. int conv_charset(const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen) {  
  9.     iconv_t conv = iconv_open(dest, src);  
  10.     if ( conv == (iconv_t) -1 )  
  11.         return -1;  
  12.     memset(output, 0, olen);  
  13.     if ( iconv(conv, &input, &ilen, &output, &olen) )  
  14.         return -1;  
  15.     iconv_close(conv);  
  16.     return 0;  
  17. }  
  18.   
  19. int main(int argc, char **argv) {  
  20.     if ( argc != 2 && argc != 3 ) {  
  21.         printf("Usage: %s stock_code [end_point]\n", argv[0]);  
  22.         exit(-1);  
  23.     }  
  24.   
  25.     struct soap soap;  
  26.     soap_init(&soap);  
  27.     soap_set_mode(&soap, SOAP_C_UTFSTRING);  
  28.   
  29.     struct _ns1__getStockInfoByCode request;  
  30.     struct _ns1__getStockInfoByCodeResponse response;  
  31.   
  32.     request.theStockCode = argv[1];  
  33.     char *endpoint = NULL;  
  34.     if ( argc == 3 )  
  35.         endpoint = argv[2];  
  36.     if ( soap_call___ns3__getStockInfoByCode(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {  
  37.         int element_counter = response.getStockInfoByCodeResult->__sizestring;  
  38.         int i = 0;  
  39.         for ( i = 0; i < element_counter; i++ ) {  
  40.             switch ( i ) {  
  41.                 case 0  : printf("Stock code        : "); break;  
  42.                 case 1  : printf("Stock name        : "); break;  
  43.                 case 2  : printf("Timestamp         : "); break;  
  44.                 case 3  : printf("Latest price      : "); break;  
  45.                 case 4  : printf("Closing price T-1 : "); break;  
  46.                 case 5  : printf("Opening price     : "); break;  
  47.                 case 6  : printf("Ups and downs     : "); break;  
  48.                 case 7  : printf("Mininum price     : "); break;  
  49.                 case 8  : printf("Maxinum price     : "); break;  
  50.                 case 9  : printf("Amount of up/down : "); break;  
  51.                 case 10 : printf("Trading volume    : "); break;  
  52.                 case 11 : printf("Trading amount    : "); break;  
  53.                 case 12 : printf("Buy price         : "); break;  
  54.                 case 13 : printf("Sell price        : "); break;  
  55.                 case 14 : printf("Agency trans      : "); break;  
  56.                 case 15 : printf("Buy  1            : "); break;  
  57.                 case 16 : printf("Buy  2            : "); break;  
  58.                 case 17 : printf("Buy  3            : "); break;  
  59.                 case 18 : printf("Buy  4            : "); break;  
  60.                 case 19 : printf("Buy  5            : "); break;  
  61.                 case 20 : printf("Sell 1            : "); break;  
  62.                 case 21 : printf("Sell 2            : "); break;  
  63.                 case 22 : printf("Sell 3            : "); break;  
  64.                 case 23 : printf("Sell 4            : "); break;  
  65.                 case 24 : printf("Sell 5            : "); break;  
  66.                 default : break;  
  67.             }  
  68.             //printf("%s\n", response.getStockInfoByCodeResult->string[i]);  
  69.             size_t ilen = strlen(response.getStockInfoByCodeResult->string[i]);  
  70.             char output[OUTPUT_LEN];  
  71.             if ( conv_charset("GBK""UTF-8", response.getStockInfoByCodeResult->string[i], ilen, output, OUTPUT_LEN) )  
  72.                 printf("%s\n", response.getStockInfoByCodeResult->string[i]);  
  73.             else  
  74.                 printf("%s\n", output);  
  75.         }  
  76.     }  
  77.     else {  
  78.         soap_print_fault(&soap, stderr);  
  79.     }  
  80.   
  81.     soap_destroy(&soap);  
  82.     soap_end(&soap);  
  83.     soap_done(&soap);  
  84.     return 0;  
  85. }  

测试成功,如下图:

 

我们用一个天气预报客户端的例子,简述一下gSOAP输入的中文文本乱码的问题。

 

Webxml.com.cn提供的天气预报web服务,endpoint地址是:http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx,大家可以点击进去,查看一下该服务的所有对外提供的接口。其中,利用getWeatherbyCityName接口,可以按给定的城市名字查询该城市的天气预报,如果输入的城市名字不能识别,将统一返回北京的天气预报。

 

根据前三节的内容,我们可以很快地准备好其客户端存根程序:

1.     mkdir –p weather

2.     cd weather

3.     ../wsdl2h -c -o weather.h http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

4.     ../../bin/linux386/soapcpp2 –C –L –x weather.h

 

由于程序并不复杂,直接给出其源代码:

  1. #include <iconv.h>  
  2.   
  3. #include "soapH.h"  
  4. #include "WeatherWebServiceSoap12.nsmap"  
  5.   
  6. #define OUTPUT_LEN 2048  
  7.   
  8. int conv_charset(const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen) {  
  9.     iconv_t conv = iconv_open(dest, src);  
  10.     if ( conv == (iconv_t) -1 )  
  11.         return -1;  
  12.     memset(output, 0, olen);  
  13.     if ( iconv(conv, &input, &ilen, &output, &olen) )  
  14.         return -1;  
  15.     iconv_close(conv);  
  16.     return 0;  
  17. }  
  18.   
  19. int main(int argc, char **argv) {  
  20.     if ( argc != 2 && argc != 3 ) {  
  21.         printf("Usage: %s city_name [end_point]\n", argv[0]);  
  22.         exit(-1);  
  23.     }  
  24.   
  25.     struct soap soap;  
  26.     soap_init(&soap);  
  27.     soap_set_mode(&soap, SOAP_C_UTFSTRING);  
  28.   
  29.     struct _ns1__getWeatherbyCityName request;  
  30.     struct _ns1__getWeatherbyCityNameResponse response;  
  31.   
  32.     size_t ilen = strlen(argv[1]);  
  33.     char output[OUTPUT_LEN];  
  34.     if ( conv_charset("UTF-8""GBK", argv[1], ilen, output, OUTPUT_LEN) )  
  35.         request.theCityName = argv[1];  
  36.     else  
  37.         request.theCityName = output;  
  38.   
  39.     char *endpoint = NULL;  
  40.     if ( argc == 3 )  
  41.         endpoint = argv[2];  
  42.         if ( soap_call___ns3__getWeatherbyCityName(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {  
  43.         int element_counter = response.getWeatherbyCityNameResult->__sizestring;  
  44.         int i = 0;  
  45.         for ( i = 0; i < element_counter; i++ ) {  
  46.             switch ( i ) {  
  47.                 case 0  : printf("Province          : "); break;  
  48.                 case 1  : printf("City              : "); break;  
  49.                 case 2  : printf("City code         : "); break;  
  50.                 case 3  : printf("City pic. name    : "); break;  
  51.                 case 4  : printf("Timestamp         : "); break;  
  52.                 case 5  : printf("Temp. of today    : "); break;  
  53.                 case 6  : printf("Summary           : "); break;  
  54.                 case 7  : printf("Wind              : "); break;  
  55.                 case 8  : printf("Icon 1            : "); break;  
  56.                 case 9  : printf("Icon 2            : "); break;  
  57.                 case 10 : printf("Description       : "); break;  
  58.                 case 11 : printf("Reserved          : "); break;  
  59.                 case 12 : printf("Temp. of tomorrow : "); break;  
  60.                 case 13 : printf("Summary           : "); break;  
  61.                 case 14 : printf("Wind              : "); break;  
  62.                 case 15 : printf("Icon 1            : "); break;  
  63.                 case 16 : printf("Icon 2            : "); break;  
  64.                 case 17 : printf("Temp. of af. tmr. : "); break;  
  65.                 case 18 : printf("Summary           : "); break;  
  66.                 case 19 : printf("Wind              : "); break;  
  67.                 case 20 : printf("Icon 1            : "); break;  
  68.                 case 21 : printf("Icon 2            : "); break;  
  69.                 case 22 : printf("Introduction      : "); break;  
  70.                 default : break;  
  71.             }  
  72.             ilen = strlen(response.getWeatherbyCityNameResult->string[i]);  
  73.             if ( conv_charset("GBK""UTF-8", response.getWeatherbyCityNameResult->string[i], ilen, output, OUTPUT_LEN) )  
  74.                 printf("%s\n", response.getWeatherbyCityNameResult->string[i]);  
  75.             else  
  76.                 printf("%s\n", output);  
  77.         }  
  78.     }  
  79.     else {  
  80.         soap_print_fault(&soap, stderr);  
  81.     }  
  82.   
  83.     soap_destroy(&soap);  
  84.     soap_end(&soap);  
  85.     soap_done(&soap);  
  86.     return 0;  
  87. }  

编译命令是:gcc -O2 -o weather weather.c soapC.c soapClient.c ../../stdsoap2.c -I../.. -L../.. –lgsoap

 

基本上与上一节的股票信息客户端差不多,唯一不同的是,作为输入参数的城市名字,首先需要iconv转换编码,从GBK转到UTF-8,才可以提交给服务端。各位可以试一下,不作转换的话,无论输入什么,服务端只会返回北京的天气预报,因为传入的参数在服务端产生了乱码。

 

以下为正常的执行结果,输入广州,可以得到广州的天气预报:


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP