The power of C, the power of MD

A problem is a chance to do your best
posts - 11, comments - 22, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

使用gSOAP开发实例(3) iconv解决中文乱码问题

Posted on 2010-08-17 12:01 roy 阅读(2864) 评论(5)  编辑 收藏 引用 所属分类: C/C++
电信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编码,从而修改客户端程序以解决乱码问题。

#include <iconv.h>

#include 
"soapH.h"
#include 
"ChinaStockWebServiceSoap12.nsmap"

#define OUTPUT_LEN 32

int conv_charset(const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen) {
    iconv_t conv 
= iconv_open(dest, src);
    
if ( conv == (iconv_t) -1 )
        
return -1;
    memset(output, 
0, olen);
    
if ( iconv(conv, &input, &ilen, &output, &olen) )
        
return -1;
    iconv_close(conv);
    
return 0;
}

int main(int argc, char **argv) {
    
if ( argc != 2 && argc != 3 ) {
        printf(
"Usage: %s stock_code [end_point]\n", argv[0]);
        exit(
-1);
    }

    
struct soap soap;
    soap_init(
&soap);
    soap_set_mode(
&soap, SOAP_C_UTFSTRING);

    
struct _ns1__getStockInfoByCode request;
    
struct _ns1__getStockInfoByCodeResponse response;

    request.theStockCode 
= argv[1];
    
char *endpoint = NULL;
    
if ( argc == 3 )
        endpoint 
= argv[2];
    
if ( soap_call___ns3__getStockInfoByCode(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {
        
int element_counter = response.getStockInfoByCodeResult->__sizestring;
        
int i = 0;
        
for ( i = 0; i < element_counter; i++ ) {
            
switch ( i ) {
                
case 0  : printf("Stock code        : "); break;
                
case 1  : printf("Stock name        : "); break;
                
case 2  : printf("Timestamp         : "); break;
                
case 3  : printf("Latest price      : "); break;
                
case 4  : printf("Closing price T-1 : "); break;
                
case 5  : printf("Opening price     : "); break;
                
case 6  : printf("Ups and downs     : "); break;
                
case 7  : printf("Mininum price     : "); break;
                
case 8  : printf("Maxinum price     : "); break;
                
case 9  : printf("Amount of up/down : "); break;
                
case 10 : printf("Trading volume    : "); break;
                
case 11 : printf("Trading amount    : "); break;
                
case 12 : printf("Buy price         : "); break;
                
case 13 : printf("Sell price        : "); break;
                
case 14 : printf("Agency trans      : "); break;
                
case 15 : printf("Buy  1            : "); break;
                
case 16 : printf("Buy  2            : "); break;
                
case 17 : printf("Buy  3            : "); break;
                
case 18 : printf("Buy  4            : "); break;
                
case 19 : printf("Buy  5            : "); break;
                
case 20 : printf("Sell 1            : "); break;
                
case 21 : printf("Sell 2            : "); break;
                
case 22 : printf("Sell 3            : "); break;
                
case 23 : printf("Sell 4            : "); break;
                
case 24 : printf("Sell 5            : "); break;
                
default : break;
            }
            
//printf("%s\n", response.getStockInfoByCodeResult->string[i]);
            size_t ilen = strlen(response.getStockInfoByCodeResult->string[i]);
            
char output[OUTPUT_LEN];
            
if ( conv_charset("GBK""UTF-8", response.getStockInfoByCodeResult->string[i], ilen, output, OUTPUT_LEN) )
                printf(
"%s\n", response.getStockInfoByCodeResult->string[i]);
            
else
                printf(
"%s\n", output);
        }
    }
    
else {
        soap_print_fault(
&soap, stderr);
    }

    soap_destroy(
&soap);
    soap_end(
&soap);
    soap_done(
&soap);
    
return 0;
}

测试成功,如下图:
 


http://blog.csdn.net/yui/archive/2010/07/21/5753879.aspx

Feedback

# re: 使用gSOAP开发实例(3) iconv解决中文乱码问题  回复  更多评论   

2010-08-17 14:05 by 毛毛
楼主试试这里提到的方法:
http://www.cppprog.com/2009/0723/138_2.html

soap sp;
soap_init(&sp);
soap_set_mode(&sp, SOAP_C_UTFSTRING);
sp.mode |= SOAP_C_UTFSTRING; //多加一句这个

# re: 使用gSOAP开发实例(3) iconv解决中文乱码问题  回复  更多评论   

2010-08-17 14:52 by roy
@毛毛

谢谢你,不过我写本节之前已经试过了,不OK

# re: 使用gSOAP开发实例(3) iconv解决中文乱码问题  回复  更多评论   

2010-08-19 22:14 by 普派
sp.mode |= SOAP_C_UTFSTRING; //多加一句这个

# re: 使用gSOAP开发实例(3) iconv解决中文乱码问题  回复  更多评论   

2010-08-19 23:32 by roy
@普派

It didn't work. Therefore, I had to find other ways.

# re: 使用gSOAP开发实例(3) iconv解决中文乱码问题  回复  更多评论   

2010-08-22 20:05 by 毛毛
加了sp.mode |= SOAP_C_UTFSTRING;以后,就是以UTF8来传送了,也就是说,发送时我们要转码成UTF8,收到的数据也是UTF8的,要转回本地编码或UNICODE编码来输出。

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理