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++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2010年9月6日

     摘要: 上一节介绍了怎样实现基本认证(Basic Authentication,以下简称basic方式),望文生义,也就是最简单的用户验证方式,本节稍微深入一些,介绍用户名令牌认证(Usernametoken Authentication,以下简称usernametoken方式)。  阅读全文

posted @ 2010-09-06 23:39 roy 阅读(9356) | 评论 (0)编辑 收藏

2010年9月4日

     摘要:   阅读全文

posted @ 2010-09-04 18:51 roy 阅读(5357) | 评论 (0)编辑 收藏

2010年9月3日

gSOAP 号称是跨平台的工具包,不过毕竟是属于 g 字头的,如果没有了一系列 GNU 组件的支持,在其他类 Unix 系统编译也会遇到不少困难。

 

gSOAP README 说得也不是很清楚,只提到依赖于这些组件:

1. Automake tools (make and GNU m4) to configure and build

2. Bison http://www.gnu.org/software/bison or the alternative Yacc

3. Flex http://flex.sourceforge.net

4. OpenSSL (for optional HTTPS) http://www.openssl.org

5. Zlib (for optional compression) http://www.zlib.net

6. Pthreads or win32 threads (optional)

 

实际上,我在 HP-UX 下编译 gSOAP 的时候发现,要成功编译,还需要安装 autoconf gawk make ,为解决中文乱码问题,还需要安装 libiconv 。虽然原系统就有 awk make ,但是由于版本问题,编译时出错。所以,建议大家编译最新版的 gSOAP-2.7.17 时,按一下顺序安装组件:

1.     autoconf-2.66 (http://ftp.gnu.org/gnu/autoconf/ )

autoconf 是一个用于生成可以自动地配置软件源代码包以适应多种 Unix 类系统的 shell 脚本的工具。

2.     automake-1.10 (http://ftp.gnu.org/gnu/automake/ )

automake 是一个从文件 Makefile.am 自动生成 Makefile.in 的工具。每个 Makefile.am 基本上是一系列 make 的宏定义( make 规则也会偶尔出现)。生成的 Makefile.in 服从 GNU Makefile 标准。

3.     m4-1.4.14 (http://ftp.gnu.org/gnu/m4/ )

m4 是一个宏处理器。

4.     gawk-3.1.8 (http://ftp.gnu.org/gnu/gawk/ )

awk 地球人都知道。 HP-UX 自带的 awk 不是 GNU 的,编译 gSOAP 时执行某些语句出错,因此在编译 gSOAP 时要使用 GNU 新版本。

5.     make-3.81 (http://ftp.gnu.org/gnu/make/ )

make 也是地球人都知道。 HP-UX 自带的 make 编译 gSOAP 时会出错。

6.     bison-2.4 (http://ftp.gnu.org/gnu/bison/ )

语法分析生成器。

7.     flex-2.5.35 (http://flex.sourceforge.net/ )

词法分析生成器。

8.     zlib-1.2.5 (http://www.zlib.net/ )

gzip LZW 压缩库。

9.     libiconv-1.13.1 (http://ftp.gnu.org/pub/gnu/libiconv/ )

字符编码转换工具,上一节有介绍。

 

openssl 原来就已经有,无需安装。如果没有或者版本很低,可以到这里下载: http://www.openssl.org/source/

 

补充事项:

1.     如何判断某个组件是否需要安装? 很简单,到 LFS 官方网站参考用户手册: http://www.linuxfromscratch.org/lfs/view/stable/ ,查看一下该组件包含的 Installed program ,然后在命令行使用 which 命令找一下,如果找不到,可以肯定需要安装

 

2.     如何判断某个组件是否需要升级? 如果通过上述方法能够找到已安装的组件,但是文件的时间比较久远,而且不支持 —help 参数查看帮助信息或者 —version 参数查看版本信息,几乎可以肯定需要升级,因为比较新的 GNU 程序一般都支持这些参数。如果通过 --version 显示版本较低,也应该升级

 

3.     上述组件的安装一般都是 ./configure && make && make install 三部曲。如果没有 root 权限,可以使用 ./configure --prefix=/path/to/your/directory 指定合法的安装路径,然后根据需要指定 PATH SHLIB_PATH 环境变量。千万要注意, HP-UX 的动态链接库的环境变量是 SHLIB_PATH ,而不是和 Linux 下的 LD_LIBRARY_PATH

 

4.     设置环境变量的时候也要注意,如果系统中已经有旧版本的组件,并且新旧版本不在同一目录, export 环境变量的时候要把新版本组件所在的 lib 目录居前 ,这样系统才能优先搜索得到

 

5.     HP-UX 下编译 flex-2.5.35 时会遇到一个棘手的问题

ld: Unsatisfied symbol "rpl_realloc" in file dfa.o

1 errors.

collect2: ld returned 1 exit status

 

rpl_realloc 为关键字搜索,发现它出现在 configure 步骤产生的 config.h 当中

/* Define to rpl_realloc if the replacement function should be used. */

#define realloc rpl_realloc

 

看样子,可能是为了避免有些系统没有 realloc ,而转用 rpl_realloc 代替。这个 rpl_realloc 不知是哪个系统的函数, HP-UX 应该可以使用 realloc 这个标准 C 函数呀!于是,把这一行注释了,重新 make 就正常了

 

6.     gSOAP-2.7.17 的编译指定要 automake-1.10 版本,如果像我那样不慎安装了 automake-1.11 ,需要自行在其 bin 目录创建两个链接,否则 gSOAP 就是傻到不认帐!

aclocal-1.10 -> aclocal-1.11

automake-1.10 -> automake-1.11

 

7.     gSOAP 的傻事还不止一件,它只认 flex 的动态库而不认静态库 ,偏偏 flex 只安装了静态库。所以,安装 flex 之后,需要手动编译以生成 libfl.so ,然后再拷贝到其 lib 目录。

gcc -shared -fPCI -o libfl.so libmain.o libyywrap.o

此外,还需要在其 lib 目录创建两个链接,其中第一个是 LFS 为保持 lex flex 的兼容性而建议的,至于第二个,完全是迁就 gSOAP 的坏脾气

libl.so -> libfl.so

libl.so.1 -> libl.so

 

如果上述准备工作全部完毕,那么即可正式编译 gSOAP 。编译步骤同样是 ./configure && make && make install ,似乎乏善可陈。但是, gSOAP-2.7.17 似乎有一个 bug ,在 HP-UX 下编译会报错:

stdsoap2_cpp.cpp: In function 'size_t frecv(soap*, char*, size_t)':

stdsoap2_cpp.cpp:876: error: invalid conversion from 'socklen_t*' to 'int*'

stdsoap2_cpp.cpp:876: error:   initializing argument 6 of 'int recvfrom(int, void*, int, int, void*, int*)'

stdsoap2_cpp.cpp: In function 'int tcp_connect(soap*, const char*, const char*, int)':

……

 

一大堆错误信息,其实是指向同一个错误: invalid conversion from 'socklen_t*' to 'int*'

 

首先,使用 find 命令查找 stdsoap2_cpp.cpp 只有一个

> find . -name "stdsoap2_cpp.cpp"

./gsoap/stdsoap2_cpp.cpp

 

然后,根据错误信息,查看该源程序的 876 行附近,函数的第六个参数,也就是最后一个参数 k SOAP_SOCKLEN_T 类型的

 

接着,查找所有的头文件,看看该类型是哪个文件定义的

> find . -name "*.h" | xargs grep -l SOAP_SOCKLEN_T

./gsoap/samples/calc_vs2005/calc_vs2005/stdsoap2.h

./gsoap/samples/wsse/stdsoap2.h

./gsoap/stdsoap2.h

./gsoap/VisualStudio2005/wsdl2h/wsdl2h/stdsoap2.h

 

很明显,就在 ./gsoap/stdsoap2.h 中。 Vi 之,在 709 行开始其定义:

   709  /* Portability: define SOAP_SOCKLEN_T */

   710  #if defined(_AIX)

   711  # if defined(_AIX43)

   712  #  define SOAP_SOCKLEN_T socklen_t

   713  # else

   714  #  define SOAP_SOCKLEN_T int

   715  # endif

   716  #elif defined(SOCKLEN_T)

   717  # define SOAP_SOCKLEN_T SOCKLEN_T

   718  #elif defined(__socklen_t_defined) || defined(_SOCKLEN_T) || defined(CYGWIN) || defined(FREEBSD) || defined(__FreeBSD__) || defined(OPENBSD) || define

d(__QNX__) || defined(QNX) || defined(OS390) || defined(HP_UX)

   719  # define SOAP_SOCKLEN_T socklen_t

   720  #elif defined(IRIX) || defined(WIN32) || defined(__APPLE__) || defined(SUN_OS) || defined(OPENSERVER) || defined(TRU64) || defined(VXWORKS)

   721  # define SOAP_SOCKLEN_T int

   722  #else

   723  # define SOAP_SOCKLEN_T size_t

   724  #endif

 

注意 718 719 行, gSOAP-2.7.17 HP-UX 下,把 SOAP_SOCKLEN_T 定义为 socklen_t ,而其它操作系统不是定义为 int 就定义为 size_t ,再联系之前的错误信息 invalid conversion from 'socklen_t*' to 'int*' ,很清楚了,只要在 719 行把 socklen_t 改为 int 就肯定能够在 HP-UX 下编译通过了。或者严谨一些,把 718 行的 defined(HP_UX) 移到 720 行最后也可以。

 

上面的问题解决了,继续编译工作,很可能会遇上另一个问题

/usr/lib/hpux32/dld.so: Unsatisfied data symbol 'yylsp' in load module '/usr/lib/hpux32/libl.so.1'.

/usr/lib/hpux32/dld.so: Unsatisfied data symbol 'yyolsp' in load module '/usr/lib/hpux32/libl.so.1'.

/usr/lib/hpux32/dld.so: Unsatisfied data symbol 'yyfnd' in load module '/usr/lib/hpux32/libl.so.1'.

……

 

这是由于系统原来就装有 flex ,但不是最新版本,结果系统搜索到旧版本的 libl.so.1 而搜索不到新版本 libl.so.1 ,这就是为什么我在前面要特别强调, export 环境变量的时候,要确保新版本所在的路径在前面,并且要在 flex lib 目录建立两个链接的原因。

 

按照上述步骤和错误处理方法,在 HP-UX 下编译 gSOAP 应该是不成问题的,推而广之,在其它 Unix 下编译 gSOAP 也应该差不多。

 

最后一个小问题是,在 HP-UX 下要使用刚刚编译出来的 soapcpp2 生成存根程序,而不要使用前四节在 linux 目录下的 soapcpp2

 

> ../../src/soapcpp2 -C -L -x stock.h

 

更进一步,如果在 HP-UX 下,需要用到 libxml2 解析 SOAP 响应消息,除了编译源代码之外,也可以直接到下列网址下载基于 HP-UX 的二进制包:

http://hpux.connect.org.uk/hppd/hpux/Gnome/libxml2-2.7.7/

 

这个地址提供了几种版本的二进制包,下载之前应该在命令行输入 uname –a 查看一下当前的操作系统信息:

> uname -a

HP-UX hostname B.11.23 U ia64 0850816723 unlimited-user license

 

根据以上信息,应当下载 Operating System HP-UX 11i v2(HP-UX 11.23) Architecture Itanium 2 的二进制包

 

下载的包是 libxml2-2.7.7-ia64-11.23.depot.gz 。把它解压后,有 root 权限的可以使用 HP-UX 专门的包管理工具安装。没有 root 权限也不要紧, depot 其实就是一个 tar 包,可以直接使用 tar 解包,把解包后的文件移动到合适的目录,再设置好 PATH SHLIB_PATH 环境变量即可。

http://blog.csdn.net/yui/archive/2010/08/09/5799465.aspx

posted @ 2010-09-03 23:02 roy 阅读(2151) | 评论 (1)编辑 收藏

2010年8月30日

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

 

前面四节的教程,分别采用了股票信息和天气预报的例子。而这两个实例有一个共同点,SOAP响应消息的数据结构相对简单,只需要按拟定的次序,事先约定返回数据代表的意义,就能够实现无歧义的沟通。这就使得gSOAP能够以字符串数组的形式,定义返回结果,再加上一个整型变量,指示返回结果的个数。

 

查看一下这两个实例的soapStub.h,可以发现,它们的结果集定义正是这样的:

 

struct ns1__ArrayOfString
{
        
int __sizestring;       /* sequence of elements <string> */
        
char **string;  /* optional element of type xsd:string */
};

 


但是,如果服务端返回的是一个相对复杂的结果集,事情就不那么好办了。例如,一个提供外汇汇率的Web Service,服务端会同时返回日元、瑞郎、英镑、欧元、澳元、加元、港币合计七种货币兑换美元的汇率情报,每种汇率情报又包括货币代码、当前汇率、涨跌幅、买入价、卖出价、时间戳等多个子项。显然,这不是一个线性结构,而是一个树形结构,就不能使用ArrayOfString来表示了。

 

这个案例的End point是:

http://webservice.webxml.com.cn/WebServices/ExchangeRateWebService.asmx

其WSDL是:

http://webservice.webxml.com.cn/WebServices/ExchangeRateWebService.asmx?wsdl

 

参考前面四节的内容,快速建立其存根程序,不再累述。

 

我们要实现的API是getExchangeRate,在soapStub.h中搜索,可以发现其返回结果集最终的定义是:

 

struct _ns1__getExchangeRateResponse_getExchangeRateResult
{
        
char *xsd__schema;      /* required element of type xsd:schema */
        
char *__any;
};

 

仅仅是两个字符串!于是,最初版本的外汇汇率客户端程序只能这样写:

#include <iconv.h>

#include 
"soapH.h"
#include 
"ExchangeRateWebServiceSoap12.nsmap"

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 type [end_point]\n", argv[0]);
        printf(
"\ttype = A : all rate\n");
        printf(
"\ttype = B : basic rate\n");
        printf(
"\ttype = C : cross rate\n");
        exit(
-1);
    }

    
struct soap soap;
    soap_init(
&soap);
    
// don't set is OK
    
//soap_set_mode(&soap, SOAP_C_UTFSTRING);

    
struct _ns1__getExchangeRate request;
    
struct _ns1__getExchangeRateResponse response;

    request.theType 
= argv[1];
    
char *endpoint = NULL;
    
if ( argc == 3 )
        endpoint 
= argv[2];
    
if ( soap_call___ns3__getExchangeRate(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {
        printf(
"%s\n", response.getExchangeRateResult->xsd__schema);
        printf(
"----------\n");
        
int ilen = strlen(response.getExchangeRateResult->__any);
        
int olen = ilen * 2;
        
char *output = (char *) malloc(sizeof(char* olen);
        conv_charset(
"GBK""UTF-8", response.getExchangeRateResult->__any, ilen, output, olen);
        printf(
"%s\n", output);
        free(output);
    }
    
else {
        soap_print_fault(
&soap, stderr);
    }

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

其中,xsd__schema没有中文字符,而__any含有中文字符,需要转换成GBK编码,具体可以参考前面两节。

 

编译执行,输出结果如下图:

 

 

 

可以看出,服务端返回的两个长字符串实际上都是基于XML形式的。gSOAP能够自动帮我们完成的也就到此为止,剩下的需要我们自力更生了。

 

不过,大家也不用头疼,我们还有另外一个利器——libxml2!网上有很多关于libxml2的教程,所以我也不必多说,只要利用其中几个函数和语句即可。

 

1.     xmlParseMemory,字符串转为XML文档

2.     xmlDocGetRootElement,获取XML文档根节点

3.     xmlStrcmp,比较XML字符串,与strcmp差不多

4.     curr = curr->xmlChildrenNode,XML节点指针指向第一个子节点

5.     curr = curr->next,XML节点指针指向下一个兄弟节点

6.     xmlNodeGetContent,获取XML节点的内容

7.     xmlFreeDoc,释放节点,与free差不多

 

最终的外汇汇率客户端程序如下:

 

#include <iconv.h>
#include 
<libxml/parser.h>
#include 
<libxml/xmlmemory.h>

#include 
"soapH.h"
#include 
"ExchangeRateWebServiceSoap12.nsmap"

#define FIELD_LEN 16

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 type [end_point]\n", argv[0]);
        printf(
"\ttype = A : all rate\n");
        printf(
"\ttype = B : basic rate\n");
        printf(
"\ttype = C : cross rate\n");
        exit(
-1);
    }

    
struct soap soap;
    soap_init(
&soap);
    
// don't set is OK
    
//soap_set_mode(&soap, SOAP_C_UTFSTRING);

    
struct _ns1__getExchangeRate request;
    
struct _ns1__getExchangeRateResponse response;

    request.theType 
= argv[1];
    
char *endpoint = NULL;
    
if ( argc == 3 )
        endpoint 
= argv[2];
    
if ( soap_call___ns3__getExchangeRate(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {
        
int len = strlen(response.getExchangeRateResult->__any);
        xmlDocPtr pdoc 
= xmlParseMemory(response.getExchangeRateResult->__any, len);
        xmlNodePtr root 
= xmlDocGetRootElement(pdoc);
        xmlNodePtr curr 
= root;
        
while ( xmlStrcmp(curr->name, (const xmlChar *"getExchangeRate") )
            curr 
= curr->xmlChildrenNode;
        
for ( curr = curr->xmlChildrenNode; curr; curr = curr->next ) {
            xmlNodePtr data;
            
for ( data = curr->xmlChildrenNode; data; data = data->next ) {
                
char ifield[FIELD_LEN];
                
char ofield[FIELD_LEN];
                strcpy(ifield, xmlNodeGetContent(data));
                
if ( conv_charset("GBK""UTF-8", ifield, strlen(ifield), ofield, FIELD_LEN) )
                    printf(
"%s\t%s\n", data->name, ifield);
                
else
                    printf(
"%s\t%s\n", data->name, ofield);
            }
            printf(
"\n");
        }
        xmlFreeDoc(pdoc);
    }
    
else {
        soap_print_fault(
&soap, stderr);
    }

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

 


编译时,需要链接libxml2库,同时指定头文件所在路径:

gcc -O2 -o exchange exchange.c soapC.c soapClient.c ../../stdsoap2.c -I../.. -I/usr/include/libxml2 -L../.. -lgsoap -lxml2

 

执行结果(部分)如下:

 

-bash-3.2$ ./exchange B

Code    JPY

Currency        日元

ClosePrice      87.08

DiffPercent     -0.29%

DiffAmount      -0.25

OpenPrice       87.5

HighPrice       87.71

LowPrice        87.04

Range   0.77%

BuyPrice        87.08

SellPrice       87.12

ChangeColor     Green

DataTime        16:57:54

 

Code

CHF

Currency        瑞郎

ClosePrice      1.0552

DiffPercent     0.16%

DiffAmount      0.0017

OpenPrice       1.054

HighPrice       1.0552

LowPrice        1.0498

Range   0.51%

BuyPrice        1.0552

SellPrice       1.0556

ChangeColor     Red

DataTime        16:57:52


http://blog.csdn.net/yui/archive/2010/07/26/5767494.aspx

posted @ 2010-08-30 17:12 roy 阅读(3326) | 评论 (0)编辑 收藏

2010年8月22日

电信provisioning系统中,常常需要与远程服务器实时交换一些数据,以完成用户的请求。由于简单对象访问协议(Simple Object Access Protocol, SOAP)的流行,许多涉及到第三方的应用,我们一般都比较乐意使用SOAP来开发。不过,由于可能涉及到公司的机密,本系列教程的开发实例尽量采用在网上已经公开的Web Service资源。
 
上一节,讲解了用iconv解决gSOAP输出的中文文本乱码的问题。在本节中,我们用一个天气预报客户端的例子,简述一下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
 
由于程序并不复杂,直接给出其源代码:
#include <iconv.h>

#include 
"soapH.h"
#include 
"WeatherWebServiceSoap12.nsmap"

#define OUTPUT_LEN 2048

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 city_name [end_point]\n", argv[0]);
        exit(
-1);
    }

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

    
struct _ns1__getWeatherbyCityName request;
    
struct _ns1__getWeatherbyCityNameResponse response;

    size_t ilen 
= strlen(argv[1]);
    
char output[OUTPUT_LEN];
    
if ( conv_charset("UTF-8""GBK", argv[1], ilen, output, OUTPUT_LEN) )
        request.theCityName 
= argv[1];
    
else
        request.theCityName 
= output;

    
char *endpoint = NULL;
    
if ( argc == 3 )
        endpoint 
= argv[2];
        
if ( soap_call___ns3__getWeatherbyCityName(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {
        
int element_counter = response.getWeatherbyCityNameResult->__sizestring;
        
int i = 0;
        
for ( i = 0; i < element_counter; i++ ) {
            
switch ( i ) {
                
case 0  : printf("Province          : "); break;
                
case 1  : printf("City              : "); break;
                
case 2  : printf("City code         : "); break;
                
case 3  : printf("City pic. name    : "); break;
                
case 4  : printf("Timestamp         : "); break;
                
case 5  : printf("Temp. of today    : "); break;
                
case 6  : printf("Summary           : "); break;
                
case 7  : printf("Wind              : "); break;
                
case 8  : printf("Icon 1            : "); break;
                
case 9  : printf("Icon 2            : "); break;
                
case 10 : printf("Description       : "); break;
                
case 11 : printf("Reserved          : "); break;
                
case 12 : printf("Temp. of tomorrow : "); break;
                
case 13 : printf("Summary           : "); break;
                
case 14 : printf("Wind              : "); break;
                
case 15 : printf("Icon 1            : "); break;
                
case 16 : printf("Icon 2            : "); break;
                
case 17 : printf("Temp. of af. tmr. : "); break;
                
case 18 : printf("Summary           : "); break;
                
case 19 : printf("Wind              : "); break;
                
case 20 : printf("Icon 1            : "); break;
                
case 21 : printf("Icon 2            : "); break;
                
case 22 : printf("Introduction      : "); break;
                
default : break;
            }
            ilen 
= strlen(response.getWeatherbyCityNameResult->string[i]);
            
if ( conv_charset("GBK""UTF-8", response.getWeatherbyCityNameResult->string[i], ilen, output, OUTPUT_LEN) )
                printf(
"%s\n", response.getWeatherbyCityNameResult->string[i]);
            
else
                printf(
"%s\n", output);
        }
    }
    
else {
        soap_print_fault(
&soap, stderr);
    }

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


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

 

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

 

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


如上图,最后一段的介绍也出现了乱码,不过我认为这是putty的问题,行末的最后一个全角字符,如果只能显示一半的话,下一行开始将产生乱码,如果再遇到一个半角字符,又能显示正常了。

http://blog.csdn.net/yui/archive/2010/07/23/5758906.aspx

posted @ 2010-08-22 18:04 roy 阅读(2015) | 评论 (0)编辑 收藏

2010年8月17日

电信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

posted @ 2010-08-17 12:01 roy 阅读(2444) | 评论 (5)编辑 收藏

2010年8月14日

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

posted @ 2010-08-14 23:46 roy 阅读(2088) | 评论 (0)编辑 收藏

2010年8月2日

电信provisioning系统中,常常需要与远程服务器实时交换一些数据,以完成用户的请求。由于简单对象访问协议(Simple Object Access Protocol, SOAP)的流行,许多涉及到第三方的应用,我们一般都比较乐意使用SOAP来开发。不过,由于可能涉及到公司的机密,本系列教程的开发实例尽量采用在网上已经公开的Web Service资源。
 
gSOAP是一套开源的C/C++软件工具包,使用它能够很方便地开发SOAP网页服务和基于XML的应用程序,就像JAVA里面的axis。
 
首先,我们需要从以下地址下载最新版本的gSOAP 2.7.17:
https://sourceforge.net/projects/gsoap2/files/
 
其次,gSOAP依赖于Bison和Flex,编译gSOAP的时候会用到,如果没有,从这里下载:
Bison:http://www.gnu.org/software/bison/
Flex:http://flex.sourceforge.net/
 
关于这两个工具包的安装步骤可以参考最新的LFS手册:
http://www.linuxfromscratch.org/lfs/view/6.4/chapter06/bison.html
http://www.linuxfromscratch.org/lfs/view/6.4/chapter06/flex.html
 
如果不是root用户,没有安装权限的话,可以在configure的时候使用--prefix=/path/to/your/own/directory,指定安装路径。装好之后,修改用户目录的.profile文件,更改PATH和LD_LIBRARY_PATH环境变量,使得系统能够正确搜索到你安装后的可执行文件和库文件即可。
 
这两步准备工作完成后,我们就可以开始编译gSOAP。Linux下编译安装源代码包无非就是tar zxvf xxx,configure,make,make install,由于我不是root用户,没有安装的权限,那么不执行make install也可以使用gSOAP开发程序,只不过使用的时候常常需要指定路径。
 
现在我们的目标是开发一个获取股票信息的客户端程序。服务端采用webxml开发的WSDL,其URL是:http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx?wsdl
 
首先,在gsoap-2.7/gsoap/wsdl/下创建一个stock目录
-bash-3.2$ mkdir -p stock
 
改变当前路径为stock
-bash-3.2$ cd stock
 
使用wsdl2h生成stock.h,如果希望生成纯C代码,需要加上-c参数,否则,将会生成C++代码
-bash-3.2$ ../wsdl2h -c -o stock.h http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx?wsdl
 
**  The gSOAP WSDL/Schema processor for C and C++, wsdl2h release 1.2.17
**  Copyright (C) 2000-2010 Robert van Engelen, Genivia Inc.
**  All Rights Reserved. This product is provided "as is", without any warranty.
**  The wsdl2h tool is released under one of the following two licenses:
**  GPL or the commercial license by Genivia Inc. Use option -l for more info.
 
Saving stock.h
 
Cannot open file 'typemap.dat'
Problem reading type map file 'typemap.dat'.
Using internal type definitions for C instead.
 
 
Connecting to 'http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx?wsdl' to retrieve WSDL/XSD...
Connected, receiving...
Done reading 'http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx?wsdl'
 
To complete the process, compile with:
> soapcpp2 stock.h
 
然后,使用soapcpp2生成客户端存根程序和相关的头文件、资源文件,由于我们只开发客户端程序,所以可以指定-C参数
-bash-3.2$ ../../bin/linux386/soapcpp2 -C stock.h
 
**  The gSOAP code generator for C and C++, soapcpp2 release 2.7.17
**  Copyright (C) 2000-2010, Robert van Engelen, Genivia Inc.
**  All Rights Reserved. This product is provided "as is", without any warranty.
**  The soapcpp2 tool is released under one of the following three licenses:
**  GPL, the gSOAP public license, or the commercial license by Genivia Inc.
 
Saving soapStub.h annotated copy of the input declarations
Saving soapH.h interface declarations
Saving soapC.c XML serializers
Saving soapClient.c client calling stubs
Saving soapClientLib.c client stubs with serializers (use only for libs)
Using ns2 service name: ChinaStockWebServiceSoap
Using ns2 service style: document
Using ns2 service encoding: literal
Using ns2 service location: http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx
Using ns2 schema namespace: http://WebXml.com.cn/ChinaStockWebServiceSoap
Saving ChinaStockWebServiceSoap.getStockImageByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap.getStockImageByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap.getStockImageByteByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap.getStockImageByteByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap.getStockImage_kByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap.getStockImage_kByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap.getStockImage_kByteByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap.getStockImage_kByteByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap.getStockInfoByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap.getStockInfoByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap.nsmap namespace mapping table
Using ns3 service name: ChinaStockWebServiceSoap12
Using ns3 service style: document
Using ns3 service encoding: literal
Using ns3 service location: http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx
Using ns3 schema namespace: http://WebXml.com.cn/ChinaStockWebServiceSoap12
Saving ChinaStockWebServiceSoap12.getStockImageByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap12.getStockImageByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap12.getStockImageByteByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap12.getStockImageByteByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap12.getStockImage_kByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap12.getStockImage_kByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap12.getStockImage_kByteByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap12.getStockImage_kByteByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap12.getStockInfoByCode.req.xml sample SOAP/XML request
Saving ChinaStockWebServiceSoap12.getStockInfoByCode.res.xml sample SOAP/XML response
Saving ChinaStockWebServiceSoap12.nsmap namespace mapping table
 
Compilation successful
 
接着,就可以利用存根程序提供的接口编写客户端程序了,过程相当简单。
#include "soapH.h"
#include 
"ChinaStockWebServiceSoap12.nsmap"

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

        
struct soap soap;
        soap_init(
&soap);
        
struct _ns1__getStockInfoByCode request;
        
struct _ns1__getStockInfoByCodeResponse response;

        request.theStockCode 
= argv[1];
        
if ( soap_call___ns3__getStockInfoByCode(&soap, NULL, 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]);
                }
        }
        
else {
                soap_print_fault(
&soap, stderr);
        }

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

基本上都是套用差不多的格式,不清楚具体参数意义的话,可以参考soapcpp2生成的存根程序及其头文件。把上述代码保存为stock.c,编译命令是:
gcc -O2 -o stock stock.c soapC.c soapClient.c ../../stdsoap2.c -I../.. -L../.. –lgsoap
 
可以看到,编译时,除了stock.c,还需要包括存根程序soapC.c和soapClient.c,以及gSOAP运行时引擎stdsoap2.c,另外还需要指定头文件搜索路径、库文件搜索路径,以及告诉编译器,链接libgsoap
 
一切正常的话,就大功告成了:
-bash-3.2$ ./stock sh600000
Stock code        : sh600000
Stock name        : 浦发银行
Timestamp         : 2010-07-08 15:02:07
Latest price      : 13.79
Closing price T-1 : 13.76
Opening price     : 13.88
Ups and downs     : 0.03
Mininum price     : 13.73
Maxinum price     : 14.06
Amount of up/down : 0.22%
Trading volume    : 451017.84
Trading amount    : 62602.5809
Buy price         : 13.78
Sell price        : 13.79
Agency trans      : 34.07%
Buy  1            : 13.78 / 1622.88
Buy  2            : 13.77 / 687.10
Buy  3            : 13.76 / 785.00
Buy  4            : 13.75 / 1430.00
Buy  5            : 13.74 / 264.00
Sell 1            : 13.79 / 33.70
Sell 2            : 13.80 / 64.17
Sell 3            : 13.81 / 290.80
Sell 4            : 13.82 / 1318.70
Sell 5            : 13.83 / 647.70

 

http://blog.csdn.net/yui/archive/2010/07/08/5721877.aspx

posted @ 2010-08-02 17:43 roy 阅读(3054) | 评论 (6)编辑 收藏

2010年7月30日

libz提供了一套与gzip有关的API,libbz2提供了一套与bzip2有关的API。我们可以利用其中几个常用的函数,在自己的项目中实现压缩、解压缩功能。这两个库文件一般在linux系统中都会有,如果没有,可以分别到以下网址下载其源代码:

 

gzip: http://www.gzip.org/

bzip2: http://www.bzip.org/index.html

 

libz最有用的函数有四个:

 

gzFile gzopen(const char *path, const char *mode);

int gzclose(gzFile file);

int gzread(gzFile file, void *buf, unsigned len);

int gzwrite(gzFile file, const void *buf, unsigned len);

 

追踪其源代码的话,可以发现,gzFile也就是void *

 

libbz2最有用的函数也有四个:

 

BZFILE *BZ2_bzopen(const char *path, const char *mode);

void BZ2_bzclose(BZFILE *file);

int BZ2_bzread(BZFILE *file, void *buf, int len);

int BZ2_bzwrite(BZFILE *file, void *buf, int len);

 

追踪其源代码的话,可以发现,BZFILE也就是void

 

所以说,libz的四个函数与libbz2的四个函数,无论从名字上看,还是从参数上看,都是如出一辙的。只不过,gzopen()和gzread()可以打开和读取任何文件,而BZ2_bzopen()和BZ2_bzread()只能打开和读取bzip2压缩的文件。

 

事实上,它们与普通文件的打开、关闭、读取、写入的四个函数,基本上是对应的:

 

FILE *fopen(const char *path, const char *mode);

int fclose(FILE *fp);

int fread(void *buf, int size_of_element, int len, FILE *fp);

int fwrite(void *buf, int size_of_element, int len, FILE *fp);

 

要打开一个打算读取的二进制文件,三个打开函数的调用分别是:

gzopen("filename", "r");

BZ2_bzopen("filename", "r");

fopen("filename", "rb");

 

要打开一个打算写入的二进制文件,三个打开函数的调用分别是:

gzopen("filename", "w");

BZ2_bzopen("filename", "w");

fopen("filename", "w");

 

可以说参数的使用是基本一样的,不过gzopen()和BZ2_bzopen()的mode参数一般没有"rb"而只有"r",因为它们处理的基本上都是二进制文件,不需要特别指明。此外,mode参数还有其它用法,比如制定压缩率等,具体可以查看源代码。

 

不同的地方之一,FILE是一个关于文件信息的结构体,而不是void类型,之二,gzread()、gzwrite()、BZ2_bzread()和BZ2_bzwrite()的参数位置与fread()和fwrite()不一样,同时也省略了size_of_element参数。

 

有了这两套API,我们就可以很方便地写出程序对文件进行压缩、解压缩操作,更多的是,把压缩、解压缩功能集成到自己的项目中去,使得项目支持压缩格式。举例如下:

 

  1. 如果使用libz的API,压缩就是对源文件进行fopen()/fread()/fclose()操作,对目标文件进行gzopen()/gzwrite()/gzclose()操作;解压缩就是对源文件进行gzopen()/gzread()/gzclose()操作,对目标文件进行fopen()/fwrite()/fclose()操作
  2. 如果使用libbz2的API,压缩就是对源文件进行fopen()/fread()/fclose()操作,对目标文件进行BZ2_bzopen()/BZ2_bzwrite()/BZ2_bzclose()操作;解压缩就是对源文件进行BZ2_bzopen()/BZ2_bzread()/BZ2_bzclose()操作,对目标文件进行fopen()/fwrite()/fclose()操作

 

如果要直接使用libz和libbz2,很简单,只需要做到三件事:

1.     include头文件。把zlib.h和bzlib.h包含到项目源程序中

2.     链接库文件。如果由于权限问题不能安装库文件,需要在编译时指定库文件的路径

3.     如果库文件没有安装在系统默认的搜索路径,运行前还要修改LD_LIBRARY_PATH环境变量,使得运行时能够找到库文件

 

值得注意的是,以上列出的只是libz和libbz2里面最常用、比较高级的函数,其实,这两个库文件里还有其它底层的函数,利用这些底层函数,甚至可以解压.Z结尾的压缩文件。具体做法就要慢慢参透libz的全部源代码了。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yui/archive/2010/07/01/5707842.aspx

posted @ 2010-07-30 12:22 roy 阅读(2358) | 评论 (0)编辑 收藏

2010年7月29日

     摘要: 众所周知,C程序的主函数有两个参数,其中,第一个参数是整型,可以获得包括程序名字的参数个数,第二个参数是字符数组指针或字符指针的指针,可以按顺序获得命令行上各个字符串参数。其原形是: int main(int argc, char *argv[]); 或者 int main(int argc, char **argv);   如果有一个解析CDR的程序,名叫destroy,负责...  阅读全文

posted @ 2010-07-29 18:01 roy 阅读(1826) | 评论 (0)编辑 收藏