基本上,gsoap2 是cg (code generation 用程式產生程式)的聰明化實踐,
因為太聰明了,資質差如筆者,真難看出端倪。很難抄,不知怎麼抄??
題外話,今天在公司,把mingw底下,把gsoap2裝起來。
有圖為証
愈是會設定,愈是心虛啊。
目前初步分析,知道,client端和server是用一個soap 訊息包互傳,而這個soap結構多大呢?
以行數來講,200多行,定義一個soap 信封(envelop),算目前以來相當龐大的結構。且結構裏面有結構。
我們用五則運算(加減乘除及次方)做例子。
~/gsoap-2.8/gsoap/samples/calc
還是用gdb來trace程式。
在官網上,有一張圖,
資質好的讀者應該看得懂,而圖上的專有名詞,等下在function call上會出現。
行前設定,有兩步,
第一步是圖上的gsoap compiler的部分,
指令是
soapcpp2 -c calc.h
第二步是編譯,並放上除錯訊息給gdb用。
$ cc -o calcclient calcclient.c ../../stdsoap2.c \
soapC.c soapClient.c -g
實驗後,沒法除錯訊息,筆者複習前幾個晚上提到的用法,
$ cc calcclient.c ../../stdsoap2.c soapC.c soapC\
lient.c -g -o calcclient
然後就開工了,
$ gdb calcclient
(gdb) set args a 100 200
(gdb) b main
(gdb) run
(gdb) p soap
$1 = {
state = 1,
version = 0,
mode = 8192,
imode = 8192,
omode = 8192,
float_format = 0x806de48 "%.9G",
double_format = 0x806de4d "%.17lG",
dime_id_format = 0x806de54 "cid:id%d",
http_version = 0x806de5d "1.1",
http_content = 0x0,
encodingStyle = 0x806ca3c "",
actor = 0x0,
lang = 0x806de65 "en",
recv_timeout = 0,
send_timeout = 0,
connect_timeout = 0,
accept_timeout = 0,
socket_flags = 0,
connect_flags = 0,
............................................
中間省略
......................................
session_port = 134680564,
c_locale = 0x0,
d_stream = 0x8048c64,
z_crc = 15322400,
z_dict = 0x8070ff4 " \017\a\bp\266", <incomplete sequence \352>,
z_dict_len = 3221223128,
zlib_state = -15047,
zlib_in = 2054,
zlib_out = 13060,
z_buf = 0x452ff4 "|\375\023",
z_buflen = 134661408,
z_level = 63192,
z_ratio_in = 4.78809812e-39,
z_ratio_out = 2.14712556e-38,
dummy = 0x806c52b <__libc_csu_init+11>
}
在源碼裏是宣告,在gdb裏,是把值填入的過程,
(gdb) n
50 soap_init1(&soap, SOAP_XML_INDENT);
(gdb) s
soap_init1 (soap=0xbffe8048, mode=8192) at ../../stdsoap2.c:8617
8617 { soap_init2(soap, mode, mode);
(gdb) s
soap_init2 (soap=0xbffe8048, imode=8192, omode=8192) at ../../stdsoap2.c:8627
8627 { soap_init(soap);
(gdb) s
soap_init (soap=0xbffe8048) at ../../stdsoap2.c:8360
8360 { soap->state = SOAP_INIT;
每一枝client,先初始化(soap_init ) soap envelop。程式太長,就像
它的封包一樣長,client,只挑一些填,其他給server 填。
準備的過程中,有點漫長,可參考原理圖,
這時程式進入soapClient.c( 從calcclient.c 過來)
這裏是開始是 tool kit 自動幫你產生的code。
而裏面所有的function,實做在 stdsoap2.c
(gdb) s
soap_call_ns__add (soap=0xbffe8048,
soap_endpoint=0x806c760 "http://websrv.cs.fsu.edu/~engelen/calcserver.cgi",
soap_action=0x806c7ba "", a=100, b=200, result=0xbffe8030) at soapClient.c:23
23 if (!soap_endpoint)
(gdb) n
25 soap->encodingStyle = "";
(gdb) n
26 soap_tmp_ns__add.a = a;
(gdb) n
27 soap_tmp_ns__add.b = b;
(gdb) n
28 soap_begin(soap);
(gdb) p a
$5 = 100
(gdb) p b
$6 = 200
(gdb) n
29 soap_serializeheader(soap);
(gdb) n
30 soap_serialize_ns__add(soap, &soap_tmp_ns__add);
(gdb) n
31 if (soap_begin_count(soap))
這裏把client 端的參數,做一個串流化的動作。
64 if (soap->error)
(gdb) n
67 || soap_envelope_end_in(soap)
(gdb) n
66 if (soap_body_end_in(soap)
(gdb) n
68 || soap_end_recv(soap))
(gdb) n
66 if (soap_body_end_in(soap)
(gdb) n
68 || soap_end_recv(soap))
(gdb) n
66 if (soap_body_end_in(soap)
(gdb) n
70 if (result && soap_tmp_ns__addResponse->result)
(gdb) n
71 *result = *soap_tmp_ns__addResponse->result;
(gdb) n
72 return soap_closesock(soap);
(gdb) n
73 }
只是傳兩個數字,一路上,竟然call了這麼多function。
再來接棒給server端處理,
接收後,做好收尾的動作。
result = 300
79 soap_destroy(&soap);
(gdb) n
80 soap_end(&soap);
(gdb) n
81 soap_done(&soap);
(gdb) n
82 return 0;
(gdb) n
83 }
基本上,client端如果只是傳參數,接結果值,那還好。
如果像rss的例子,接回來是一大堆新聞摘要呢?而且可以動態的指定新聞摘要的則數,
這時候,動作相對複雜多呢!!
小結:
先從消費現成的web service,慢慢的掌握 gsoap2裏已經建好的soap function call。
server端的web service,撰寫不太困難,困難的是trace的方式,目前是CGI附在web server上,至少是兩個行程的除錯。還好gsoap有提供另一種web service的形式,可以獨立生存。
一個簡單的傳兩個數字到server端,設計者可以自動產生code來達成,想必,這個動作必有一sop(標準做業流程),有規律,程式才能自動生成。
而5則運算裏,很明顯的,code是大同小異。
掌握這個原則,單純的傳值,接值的client,可以容易舉一反三。