Linux c++ onvif客户端开发(7):struct soap包装类

10 篇文章 2 订阅

 本文是Linux c++ onvif客户端开发系列文章之一:

 可以先先看一下gsoap内存管理这篇文章。

1. 先定义一个命名空间

namespace onvif {

}

 2. 定义一个fault结构, 表示xml中soap:Fault错误信息

struct Fault {
    std::string code;
    std::string subcode;
    std::string str; // string
    std::string detail;
};

一个典型的Fault信息格式如下

<s:Envelope
    xmlns:s="http://www.w3.org/2003/05/soap-envelope"
    xmlns:sc="http://www.w3.org/2003/05/soap-encoding"
    xmlns:ter="http://www.onvif.org/ver10/error"
    xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
    xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
    xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery">
    <s:Body>
        <s:Fault>
            <s:Code>
                <s:Value>s:Sender</s:Value>
                <s:Subcode>
                    <s:Value>ter:ActionNotSupported</s:Value>
                    <s:Subcode>
                        <s:Value>ter:NotImplemented</s:Value>
                    </s:Subcode>
                </s:Subcode>
            </s:Code>
            <s:Reason>
                <s:Text xml:lang="en">This optional method is not implemented</s:Text>
            </s:Reason>
        </s:Fault>
    </s:Body>
</s:Envelope>

3. 对struct soap进行包装

class Soap {
public:
    Soap(int timeout);
    ~Soap();

    void InitHeader();
    void InitProbeType(struct wsdd__ProbeType *probe);

    int Error() { return soap_->error; }

    // 返回的xml中soap:Fault
    std::string FaultString();
    std::string FaultCode();
    std::string FaultSubcode();
    std::string FaultDetail();

    struct soap *soap() const;

    // c++中struct soap的析构函数会自动调用
    void Destroy();

    // 填写Fault信息
    void FillFault(Fault *fault = nullptr);

private:
    struct soap *soap_;
};

 4. 实现

#define SOAP_PROBE_TO "urn:schemas-xmlsoap-org:ws:2005:04:discovery"
#define SOAP_PROBE_ACTION                                                      \
    "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe"

#define SOAP_MCAST_ADDR "soap.udp://239.255.255.250:3702" // onvif规定的组播地址

#define SOAP_ITEM ""                            // 寻找的设备范围
#define SOAP_TYPES "dn:NetworkVideoTransmitter" // 寻找的设备类型

#define SOAP_SOCK_TIMEOUT (2) // socket超时时间(单秒秒)


namespace onvif {

namespace util {
// 定义 split() 函数,将字符串按指定分隔符分割成多个子字符串并存入
// vector<string> 中
static void Split(const std::string &s, char delim,
                  std::vector<std::string> &elems) {
    std::istringstream iss(s);
    for (std::string item; getline(iss, item, delim);) {
        if (!item.empty()) {
            elems.push_back(item);
        }
    }
}

int CountChar(const std::string &s, char c) {
    auto count = std::count(s.begin(), s.end(), c);
    return count;
}

} // namespace util

Soap::Soap(int timeout) {
    // There is no need to call soap_init to initialize the context
    // allocated with soap_new, since soap_new initializes the allocated
    // context.
    // https://www.genivia.com/doc/guide/html/group__group__context.html#ga87c20488b2dc680aaa7689b1d024989c
    soap_ = soap_new();
    if (!soap_)
        throw std::runtime_error("soap_new() fail");

    soap_set_namespaces(soap_, namespaces); // 设置soap的namespaces

    // 不正常数据设置成5s
    if (timeout <= 0)
        timeout = SOAP_SOCK_TIMEOUT;

    soap_->recv_timeout = timeout; // 设置超时(超过指定时间没有数据就退出)
    soap_->send_timeout = timeout;
    soap_->connect_timeout = timeout;

#if defined(__linux__) ||                                                      \
    defined(__linux) // 参考https://www.genivia.com/dev.html#client-c的修改:
    soap_->socket_flags = MSG_NOSIGNAL; // To prevent connection reset errors
#endif

    soap_set_mode(soap_,
                  SOAP_C_UTFSTRING); // 设置为UTF-8编码,否则叠加中文OSD会乱码
}

Soap::~Soap() {
    soap_destroy(soap_); // delete managed C++ objects
    soap_end(soap_);     // delete managed memory。soap_malloc
    soap_done(soap_);    // stacked
    soap_free(soap_);    /* we're done with the context */
}

/**
 * @brief 填充Header, 用于Probe操作
 *
<SOAP-ENV:Header>
    <wsa:MessageID>urn:uuid:dc8f9f8a-05b2-45c2-a63e-f5b47636af83</wsa:MessageID>
    <wsa:To
SOAP-ENV:mustUnderstand="true">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>
    <wsa:Action
SOAP-ENV:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>
</SOAP-ENV:Header>
 */
void Soap::InitHeader() {
    // T * soap_new_T(struct soap*) allocates and initializes data of type T
    // in context-managed heap memory, managed data is deleted with
    // soap_destroy (deletes C++ objects) and soap_end (deletes all other
    // data), and you can also use soap_malloc to allocate uninitialized
    // context-managed memory.
    struct SOAP_ENV__Header *header = soap_new_SOAP_ENV__Header(soap_);

    header->wsa__MessageID = (char *)soap_wsa_rand_uuid(soap_);
    header->wsa__To = soap_strdup(soap_, SOAP_PROBE_TO);
    header->wsa__Action = soap_strdup(soap_, SOAP_PROBE_ACTION);
    soap_->header = header;
}

/**
 * @brief 填充body Probe数据, 用于Probe操作
 *     <SOAP-ENV:Body>
        <wsdd:Probe>
            <wsdd:Types>dn:NetworkVideoTransmitter</wsdd:Types>
            <wsdd:Scopes/>
        </wsdd:Probe>
    </SOAP-ENV:Body>
 * @param probe
 */
void Soap::InitProbeType(struct wsdd__ProbeType *probe) {
    // 用于描述查找哪类的Web服务
    struct wsdd__ScopesType *scope = soap_new_wsdd__ScopesType(soap_);
    // soap_default_wsdd__ScopesType(soap_, scope); // 设置寻找设备的范围
    scope->__item = soap_strdup(soap_, "");

    probe->Scopes = scope;
    probe->Types = soap_strdup(soap_, SOAP_TYPES); // 设置寻找设备的类型
}

std::string Soap::FaultString() {
    const char *fault_string = soap_fault_string(soap_);
    if (!fault_string)
        return std::string();
    else
        return std::string(fault_string);
}

std::string Soap::FaultCode() {
    const char **code = soap_faultcode(soap_);
    if (code && *code)
        return std::string(*code);
    else
        return std::string();
}

std::string Soap::FaultSubcode() {
    const char *subcode = soap_fault_subcode(soap_);
    if (!subcode)
        return std::string();
    else
        return std::string(subcode);
}

std::string Soap::FaultDetail() {
    const char *detail = soap_fault_detail(soap_);
    if (!detail)
        return std::string();
    else
        return std::string(detail);
}

struct soap *Soap::soap() const {
    return soap_;
}

void Soap::Destroy() { soap_->destroy(); }

void Soap::FillFault(Fault *fault) {
    if (!fault)
        return;

    // str
    const char *fault_string = soap_fault_string(soap_);
    if (fault_string)
        fault->str.assign(fault_string);

    // code
    const char **code = soap_faultcode(soap_);
    if (code && *code)
        fault->code.assign(*code);

    // subcode
    const char *subcode = soap_fault_subcode(soap_);
    if (subcode)
        fault->subcode.assign(subcode);

    // detail
    const char *detail = soap_fault_detail(soap_);
    if (detail)
        fault->detail.assign(detail);
}

} // namespace onvif

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值