寫gsoap客戶端的懶辦法——巨集函式
阿新 • • 發佈:2018-11-15
用了兩天折騰gsoap的用法,寫了個蹩腳的客戶端,因為沒有細緻地去研究wsdl2h和soapcpp2兩個工具的引數,生成的檔案總是看上去不太好記。加上只是臨時任務就直接在centos上編碼了(絕對是壞習慣),沒有提示啥的寫錯太簡單了。為減少人為犯錯的機會,果斷用巨集函式~
巨集函式實現
網上大多關於gsoap的示例中給出的引數都比較簡單,是基本型別的。對於複雜型別的引數就需要用資料類或結構體打包一下,此時生成的介面的型別大概就會這樣:
virtual int GetUpdateTime(
ns1__GetUpdateTime *ns1__GetUpdateTime_,
ns1__GetUpdateTimeResponse &ns1__GetUpdateTimeResponse_){
......
}
乍看……反正就是要敲好多字的那種,二指彈的很不開心。but很有規律的丫 ~
沒有啥設定的時候函式呼叫啥的寫起來很清爽的樣子:
calcProxy cal;
double result = 0;
if (SOAP_OK==cal.add(1, 2, result))
{
cout << result << endl;
}
加上亂七八糟的超時丫、字元編碼啥的設定,那每個介面呼叫裡都要寫一遍,感覺自己蠢蠢的。
所以乾脆就把初始化和函式呼叫都寫成巨集函式啦~直接丟程式碼咯~
//# init soap
#define INIT_SOAP_WHICHONE(funcname, timeout, v1) \
hnxnyPortBindingProxy soapProxy; \
soap_set_mode(soapProxy.soap, SOAP_C_UTFSTRING); \
soapProxy.soap->connect_timeout = timeout; \
soapProxy.soap->send_timeout = timeout; \
soapProxy.soap->recv_timeout = timeout; \
ns##v1##__##funcname req; \
ns##v1##__##funcname##Response res;
#define INIT_SOAP(funcname, timeout) INIT_SOAP_WHICHONE(funcname, timeout, 1)
#define INIT_SOAP2(funcname, timeout) INIT_SOAP_WHICHONE(funcname, timeout, 2)
#define INIT_SOAP3(funcname, timeout) INIT_SOAP_WHICHONE(funcname, timeout, 3)
#define INIT_SOAP4(funcname, timeout) INIT_SOAP_WHICHONE(funcname, timeout, 4)
//# call soap
#define SOAP_CALL_WHICHONE(funcname, endPoint, ver) \
{ \
int soapRet = soapProxy.funcname(endPoint, NULL, &req, res); \
if (soapRet != SOAP_OK) { return ERR_OVERTIME; } \
}
#define SOAP_CALL(funcname, endPoint) SOAP_CALL_WHICHONE(funcname, endPoint, 1)
#define SOAP_CALL2(funcname, endPoint) SOAP_CALL_WHICHONE(funcname, endPoint, 2)
#define SOAP_CALL3(funcname, endPoint) SOAP_CALL_WHICHONE(funcname, endPoint, 3)
#define SOAP_CALL4(funcname, endPoint) SOAP_CALL_WHICHONE(funcname, endPoint, 4)
俺這種小打小鬧級別的巨集函式要看懂只要做到兩點就行:
- 預設巨集函式就是字元替換;
- 程式碼排版要美;
看懂了用起來就十分方便啦,以入參為類的方法示例:
// 初始化
INIT_SOAP(GetRecordings, 1000);
// 輸入
req.arg0 = &measurementPath;
req.arg1 = &startTime;
req.arg2 = &endTime;
// 介面呼叫
SOAP_CALL(GetRecordings, url);
// 輸出
results = res.return_;
注意事項
在編寫過程中遇到的幾點要注意的有
1、巨集函式中連線符
很久之前在windows下寫巨集函式,SOAP_CALL_WHICHONE
的寫法是:
#define SOAP_CALL_WHICHONE(funcname, endPoint, ver) \
{ \
int soapRet = soapProxy.##funcname(endPoint, NULL, &req, res); \
if (soapRet != SOAP_OK) { return ERR_OVERTIME; } \
}
編譯報錯指向soapProxy.##funcname
所在行: does not give a valid preprocessing token。
解決方案是去掉funcname前的連線符##
,這個地方出錯主要是因為soapProxy.
的緣故,在這種情況下連線符的解析出錯。
參考解決方案:https://bbs.csdn.net/topics/300111770
2、soapcpp2引數
因為使用了soapProxy.soap
來設定一些引數,因此在生成的時候需要使用引數-j
而不是-i
。
引數 | 作用 |
---|---|
-1 | Soap1.1繫結 |
-2 | SOAP1.2繫結 |
-C | 只生成客戶端程式碼 |
-S | 只生成伺服器端程式碼 |
-T | 生成自動測試程式碼 |
-L | 不生成 soapClientLib/soapServerLib |
-a | 用 SOAPAction 和WS-Addressing呼叫伺服器端方法 |
-A | 用 SOAPAction 呼叫伺服器端方法 |
-b | 採用char[N]這樣的方式來表示string |
-c | 生成的是C程式碼,不是C++程式碼 |
-d < path > | 將程式碼生成在 < path >下 |
-e | 生成 SOAP RPC 樣式的繫結 |
-f N | File split of N XML serializer implementations per file |
-h | 顯示一個簡要的用法資訊 |
-i | 生成的服務代理類和物件從struct soap繼承而來 |
-j | 生成的服務代理類和物件包含struct soap而來(C程式碼的唯一選擇) |
-I < path > | 包含其他檔案時使用,指明 < path > (多個的話,用`:’分割),相當於#import ,該路徑一般是gSOAP目錄下的import目錄,該目錄下有一堆檔案供soapcpp2生成程式碼時使用。 |
-n | 用於生成支援多個客戶端和伺服器端(具體內容參考gSOAP文件) |
-p < name > | 生成的檔案字首採用< name > ,而不是預設的 “soap” |
-q < name > | C++程式碼中,所有宣告的名稱空間 |
-s | 生成的程式碼在反序列化時,嚴格檢查XML的有效性 |
-t | 生成的程式碼在傳送訊息時,採用xsi:type方式 |
-u | 在 WSDL/schema 輸出檔案中不產生XML註釋 |
-v | 顯示版本資訊 |
-w | 不生成 WSDL 和 schema 檔案 |
-x | 不生成 XML 形式的傳輸訊息檔案 |
-y | 在XML 形式的傳輸訊息檔案中,包含 C/C++型別資訊 |