- 電信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;
}
#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;
}
- 測試成功,如下圖: