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 環境變量即可。
前面四節的教程,分別采用了股票信息和天氣預報的例子。而這兩個實例有一個共同點,SOAP響應消息的數據結構相對簡單,只需要按擬定的次序,事先約定返回數據代表的意義,就能夠實現無歧義的溝通。這就使得gSOAP能夠以字符串數組的形式,定義返回結果,再加上一個整型變量,指示返回結果的個數。
查看一下這兩個實例的soapStub.h,可以發現,它們的結果集定義正是這樣的:
但是,如果服務端返回的是一個相對復雜的結果集,事情就不那么好辦了。例如,一個提供外匯匯率的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中搜索,可以發現其返回結果集最終的定義是:
僅僅是兩個字符串!于是,最初版本的外匯匯率客戶端程序只能這樣寫:
其中,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差不多
最終的外匯匯率客戶端程序如下:
編譯時,需要鏈接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
基本上與上一節的股票信息客戶端差不多,唯一不同的是,作為輸入參數的城市名字,首先需要iconv轉換編碼,從GBK轉到UTF-8,才可以提交給服務端。各位可以試一下,不作轉換的話,無論輸入什么,服務端只會返回北京的天氣預報,因為傳入的參數在服務端產生了亂碼。
以下為正常的執行結果,輸入廣州,可以得到廣州的天氣預報:
http://blog.csdn.net/yui/archive/2010/07/08/5721877.aspx
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,我們就可以很方便地寫出程序對文件進行壓縮、解壓縮操作,更多的是,把壓縮、解壓縮功能集成到自己的項目中去,使得項目支持壓縮格式。舉例如下:
如果要直接使用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
我找到一個辦法,字符串追加時,事先給出目標字符串結尾所在的位置,追加時,也就不用從頭開始計算其長度了,復制的過程中,目標字符串的結尾也隨之移動,下一次再追加也就可以使用它了。以下就是優化過的string_append,與strcat相比,增加了一個整形指針以傳遞目標字符串長度的地址。
經試驗,string_append在大數組重復追加內容的情形下,優勢非常明顯。其它情形下,使用原來的strcat也就足夠了。
-bash-3.2$ ./string_append_demo
It takes 2 seconds to show the performance of string_append()
It takes 11 seconds to show the performance of strcat()
They are equal
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yui/archive/2010/05/22/5616455.aspx