写gsoap客户端的懒办法——宏函数

用了两天折腾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)

俺这种小打小闹级别的宏函数要看懂只要做到两点就行:

  1. 预设宏函数就是字符替换
  2. 代码排版要美;

看懂了用起来就十分方便啦,以入参为类的方法示例:

// 初始化
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

参数作用
-1Soap1.1绑定
-2SOAP1.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 NFile 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++类型信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值