欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中g(shù)SOAP的使用詳解

 更新時(shí)間:2021年11月03日 14:35:53   作者:time-flies  
這篇文章主要介紹了C++中g(shù)SOAP的使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

本文主要介紹C++中g(shù)SOAP的使用方法,附帶介紹SOAP協(xié)議的基礎(chǔ)知識,適用于第一次使用gSOAP的開發(fā)人員。gSOAP官網(wǎng)上的示例代碼存在一些錯誤,對初次接觸的人不太友好,本文是在官方示例calc++的基礎(chǔ)上進(jìn)行了一些補(bǔ)充、改動。

SOAP簡介

SOAP 是一種簡單的基于 XML 的協(xié)議,它使應(yīng)用程序通過 HTTP 來交換信息,具體內(nèi)容可以參考SOAP 教程。SOAP的本質(zhì)是通過HTTP協(xié)議以XML格式進(jìn)行數(shù)據(jù)交互,只不過這個(gè)XML格式的定義是大家公認(rèn)的。

使用SOAP時(shí)需注意,SOAP的XML命名空間由于版本的不同可能存在差異(如soapevn、SOAP-ENV),在調(diào)用SOAP服務(wù)前最好確認(rèn)服務(wù)器的XML格式。

gSOAP

gSOAP 有商業(yè)版、開源版兩個(gè)版本,開源版使用GPLv2開源協(xié)議,支持多個(gè)操作系統(tǒng),具體內(nèi)容參考github或者官網(wǎng)。

gSOAP提供了一組編譯工具(可以認(rèn)為是代碼生成器)和一些庫文件,簡化C/C++語言開發(fā)web服務(wù)或客戶端程序的工作,開發(fā)人員可以專注于實(shí)現(xiàn)應(yīng)用程序的邏輯:

  • 編譯工具提供了一個(gè)SOAP/XML 關(guān)于C/C++ 語言的實(shí)現(xiàn),能夠自動完成本地C或C++數(shù)據(jù)類型和XML數(shù)據(jù)結(jié)構(gòu)之間的轉(zhuǎn)換。
  • 庫文件提供了SOAP報(bào)文生成、HTTP協(xié)議通訊的實(shí)現(xiàn),及相關(guān)的配套設(shè)施,用于最終的SOAP報(bào)文的生成、傳輸。

本文使用的庫文件主要是以下幾個(gè):

  • stdsoap2.h、stdsoap2.cpp:HTTP協(xié)議的實(shí)現(xiàn)、最終的SOAP報(bào)文生成,如果是C語言則使用stdsoap2.h、stdsoap2.c
  • typemap.dat: wsdl2h工具根據(jù)wsdl文件生成頭文件時(shí)需要此文件,可以更改項(xiàng)目的xml命名空間(后面再細(xì)說)
  • threads.h:實(shí)現(xiàn)高性能的多線程服務(wù)器需要的文件,可以并發(fā)處理請求,并且在服務(wù)操作變得耗時(shí)時(shí)不會阻塞其他客戶端請求

準(zhǔn)備工作

先進(jìn)入官網(wǎng)的下載頁面,然后選擇開源版本:

也可以直接點(diǎn)擊開源版本的官方下載鏈接https://pan.baidu.com/s/156PEw9OMbzQel39Oozknow提取碼: gy4x。

將下載的壓縮包解壓(本文使用的是gsoap_2.8.117.zip),解壓后的文件放到自己習(xí)慣的位置(推薦放到C盤)。

在命令行提示符窗口中,使用cd命令進(jìn)入..\gsoap_2.8.117\gsoap-2.8\gsoap\bin\win64目錄:

注:后面需要把頭文件、typemap.dat放到該程序目錄下,生成的文件也在這里。

頭文件

使用gSOAP的編譯工具生成代碼,需要一個(gè)定義API的頭文件,此處使用官方示例中的calc.h頭文件,對兩個(gè)數(shù)字進(jìn)行加、減、乘、除或乘方運(yùn)算:。

calc.h頭文件可以通過wsdl2h工具自動生成(需要Web 服務(wù)的 WSDL文件 ),運(yùn)行的cmd命令如下:

wsdl2h -o calc.h http://www.genivia.com/calc.wsdl

也可以手動定義一個(gè)calc.h頭文件,內(nèi)容如下:

//gsoap ns service method add Sums two values
int ns__add(double a, double b, double &result);
//gsoap ns service method sub Subtracts two values
int ns__sub(double a, double b, double &result);
//gsoap ns service method mul Multiplies two values
int ns__mul(double a, double b, double &result);
//gsoap ns service method div Divides two values
int ns__div(double a, double b, double &result);
//gsoap ns service method pow Raises a to b
int ns__pow(double a, double b, double &result);

構(gòu)建客戶端應(yīng)用程序

客戶端應(yīng)用程序在命令行中運(yùn)行并使用命令行參數(shù)調(diào)用計(jì)算器 Web 服務(wù)來對兩個(gè)數(shù)字進(jìn)行加、減、乘、除或乘方運(yùn)算。

生成soap源碼

為客戶端生成服務(wù)和數(shù)據(jù)綁定接口:

soapcpp2 -j -r -CL calc.h

其中 option-j生成 C++ 代理類,option-r生成報(bào)告,option-CL僅生成客戶端,而沒有(未使用的)lib 文件。

這會生成以下幾個(gè)文件:

其中,xml文件是SOAP報(bào)文的示例,便于后期的調(diào)試,以add方法為例。

add方法的請求報(bào)文ns.add.req.xml內(nèi)容如下:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:ns="http://tempuri.org/ns.xsd">
 <SOAP-ENV:Body>
  <ns:add>
   <a>0.0</a>
   <b>0.0</b>
  </ns:add>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

add方法的響應(yīng)報(bào)文ns.add.req.xml內(nèi)容如下:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:ns="http://tempuri.org/ns.xsd">
 <SOAP-ENV:Body>
  <ns:addResponse>
   <result>0.0</result>
  </ns:addResponse>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

建立客戶端項(xiàng)目

建立一個(gè)C++的控制臺應(yīng)用項(xiàng)目,引入上面生成的幾個(gè)文件:

  • soapStub.h: 沒有注釋的純 C/C++ 頭文件語法的規(guī)范副本。
  • soapH.h:聲明 XML 序列化程序。
  • soapC.cpp: 實(shí)現(xiàn) XML 序列化程序。
  • soapProxy.h: 定義客戶端 XML 服務(wù) API 類Proxy。
  • soapProxy.cpp: 實(shí)現(xiàn)客戶端 XML 服務(wù) API 類Proxy。
  • calc.nsmap: XML 命名空間綁定表到 #include。

還需要引入gSOAP解壓目錄下的stdsoap2.h和stdsoap2.cpp文件。

為方便調(diào)試,客戶端程序示例改為固定參數(shù)調(diào)用add方法,代碼如下:

#include "soapProxy.h"
#include "ns.nsmap"
/* the Web service endpoint URL */
const char server[] = "http://localhost:8080";
int main(int argc, char** argv)
{    
    /*if (argc < 4)
    {
        fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n");
        exit(1);
    }*/
    Proxy calc(server);
    double a, b, result;
    /*a = strtod(argv[2], NULL);
    b = strtod(argv[3], NULL);*/
    a = 3;
    b = 23;
    /*switch (*argv[1])*/
    switch ('a')
    {
    case 'a':
        calc.add(a, b, result);
        break;
    case 's':
        calc.sub(a, b, result);
        break;
    case 'm':
        calc.mul(a, b, result);
        break;
    case 'd':
        calc.div(a, b, result);
        break;
    case 'p':
        calc.pow(a, b, result);
        break;
    default:
        fprintf(stderr, "Unknown command\n");
        exit(1);
    }
    if (calc.soap->error)
        calc.soap_stream_fault(std::cerr);
    else
        std::cout << "result = " << result << std::endl;
    calc.destroy(); /* clean up */
    std::cout << std::endl;
    return 0;
}

構(gòu)建服務(wù)端應(yīng)用程序

實(shí)現(xiàn)一個(gè)獨(dú)立的迭代服務(wù)器,它接受主機(jī)端口上的傳入請求,支持多線程,可以并發(fā)處理請求,并且在服務(wù)操作變得耗時(shí)時(shí)不會阻塞其他客戶端請求。

生成SOAP源碼

為服務(wù)器端生成服務(wù)和數(shù)據(jù)綁定接口:

soapcpp2 -j -r -SL calc.h

其中 option-j生成 C++ 服務(wù)類,option-r生成報(bào)告,option-SL僅生成服務(wù)器端,而沒有(未使用的)lib 文件。

生成的文件和客戶端的文件名稱一樣,只是內(nèi)容不同。

建立服務(wù)端項(xiàng)目

建立一個(gè)C++的控制臺應(yīng)用項(xiàng)目,引入的生成文件和客戶端的相同。為了支持多線程,需要引入文件threads.h。
服務(wù)端代碼如下:

#include "soapService.h"
#include "ns.nsmap"
#include "threads.h"
int port = 8080;
void* process_request(void* arg)
{
    Service* service = (Service*)arg;
    THREAD_DETACH(THREAD_ID);
    if (service)
    {
        service->serve();
        service->destroy(); /* clean up */
        delete service;
    }
    return NULL;
}
int main()
{
    Service service(SOAP_IO_KEEPALIVE);                      /* enable HTTP kee-alive */
    service.soap->send_timeout = service.soap->recv_timeout = 5; /* 5 sec socket idle timeout */
    service.soap->transfer_timeout = 30;                         /* 30 sec message transfer timeout */
    SOAP_SOCKET m = service.bind(NULL, port, 100);              /* master socket */
    if (soap_valid_socket(m))
    {
        while (soap_valid_socket(service.accept()))
        {
            THREAD_TYPE tid;
            void* arg = (void*)service.copy();
            /* use updated THREAD_CREATE from plugin/threads.h https://www.genivia.com/files/threads.zip */
            if (arg)
                while (THREAD_CREATE(&tid, (void* (*)(void*))process_request, arg))
                    Sleep(1);
        }
    }
    service.soap_stream_fault(std::cerr);
    service.destroy(); /* clean up */
    return 0;
}
/* service operation function */
int Service::add(double a, double b, double& result)
{
    result = a + b;
    return SOAP_OK;
}
/* service operation function */
int Service::sub(double a, double b, double& result)
{
    result = a - b;
    return SOAP_OK;
}
/* service operation function */
int Service::mul(double a, double b, double& result)
{
    result = a * b;
    return SOAP_OK;
}
/* service operation function */
int Service::div(double a, double b, double& result)
{
    if (b)
        result = a / b;
    else
        return soap_senderfault("Division by zero", NULL);
    return SOAP_OK;
}
/* service operation function */
int Service::pow(double a, double b, double& result)
{
    result = ::pow(a, b);
    if (soap_errno == EDOM)   /* soap_errno is like errno, but portable */
        return soap_senderfault("Power function domain error", NULL);
    return SOAP_OK;
}

打印報(bào)文

在實(shí)際調(diào)試中,需要確定SOAP協(xié)議過程中具體的報(bào)文,只需要改動stdsoap2.cpp源碼即可。參考gsoap報(bào)文打印,實(shí)現(xiàn)保存最后一次報(bào)文到特定的文件。

stdsoap2.h頭文件include下添加fstream,內(nèi)容如下:

#include "stdsoap2.h"
#include <fstream>

soap_begin_recv函數(shù)開始處添加以下代碼:

//發(fā)送完請求報(bào)文 獲取請求報(bào)文信息(作為客戶端的時(shí)候)
std::string str_reqXml = "";
std::string strBuf;
std::string::size_type pos1 = std::string::npos;
std::string::size_type pos2 = std::string::npos;
strBuf = soap->buf;
pos1 = strBuf.find("<?xml", 0);
pos2 = strBuf.find("</SOAP-ENV:Envelope>", 0);
if (pos1 != std::string::npos && pos2 != std::string::npos)
{
    str_reqXml = strBuf.substr(pos1, pos2 - pos1 + 20);
}
std::ofstream  outfile;
outfile.open("reqXml.txt");
outfile << str_reqXml;
outfile.close();

soap_body_end_in函數(shù)開始處添加以下代碼:

//接收完應(yīng)答報(bào)文 獲取應(yīng)答報(bào)文信息(作為客戶端的時(shí)候)
std::string str_resXml = "";
std::string strBuf;
std::string strEnd = "</SOAP-ENV:Envelope>";
std::string::size_type pos1 = std::string::npos;
std::string::size_type pos2 = std::string::npos;
pos1 = std::string::npos;
pos2 = std::string::npos;
soap->buf[SOAP_BUFLEN - 1] = '\0';
strBuf = soap->buf;
pos1 = strBuf.find("<?xml", 0);
pos2 = strBuf.find(strEnd, 0);
if (pos1 != std::string::npos && pos2 != std::string::npos)
{
    str_resXml = strBuf.substr(pos1, pos2 - pos1 + strEnd.length());
}
std::ofstream  outfile;
outfile.open("resXml.txt");
outfile << str_resXml;
outfile.close();

soap_recv_raw函數(shù)結(jié)尾處(return前)添加以下代碼:

//請求報(bào)文(作為服務(wù)端的時(shí)候)
std::string req_data;
req_data.assign(soap->buf, ret);
std::ofstream  outfile;
outfile.open("req_data.txt");
outfile << req_data;
outfile.close();

soap_flush_raw函數(shù)結(jié)尾處(return前)添加以下代碼:

//應(yīng)答報(bào)文(作為服務(wù)端的時(shí)候)
std::string res_data;
res_data.assign(s, n);
std::ofstream  outfile;
outfile.open("res_data.txt");
outfile << res_data;
outfile.close();

注:客戶端可以一直打印報(bào)文,服務(wù)端只能在Debug運(yùn)行時(shí)才會打印報(bào)文,應(yīng)該有其它方法可以解決。

SOAP測試

運(yùn)行上面的服務(wù)器、客戶端項(xiàng)目,可以看到運(yùn)行API調(diào)用結(jié)果,也可以使用SoapUI進(jìn)行測試。

進(jìn)入官網(wǎng)的下載鏈接:https://www.soapui.org/downloads/soapui/,下載開源版本并安裝。

打開軟件,在菜單欄的“File”中選擇“New SOAP Project”:

展開左側(cè)的項(xiàng)目,雙擊“Request”,開始進(jìn)行測試:


項(xiàng)目源碼

SoapTest提取碼: 89mu

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • C語言實(shí)現(xiàn)房屋管理系統(tǒng)

    C語言實(shí)現(xiàn)房屋管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)房屋管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • C語言中的自定義類型之結(jié)構(gòu)體與枚舉和聯(lián)合詳解

    C語言中的自定義類型之結(jié)構(gòu)體與枚舉和聯(lián)合詳解

    今天我們來學(xué)習(xí)一下自定義類型,自定義類型包括結(jié)構(gòu)體、枚舉、聯(lián)合體,小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考
    2022-06-06
  • C++ 哈夫曼樹對文件壓縮、加密實(shí)現(xiàn)代碼

    C++ 哈夫曼樹對文件壓縮、加密實(shí)現(xiàn)代碼

    這篇文章主要介紹了C++ 哈夫曼樹對文件壓縮、加密實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • C語言函數(shù)的參數(shù)使用指針

    C語言函數(shù)的參數(shù)使用指針

    這篇文章主要介紹了C語言函數(shù)的參數(shù)使用指針,本文講述了指針在作為函數(shù)參數(shù)時(shí)候的使用方法,解析值傳遞和值引用的區(qū)別案例,希望對你有所幫助
    2021-06-06
  • C++中順序表操作的示例代碼

    C++中順序表操作的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C++中順序表的基礎(chǔ)操作的相關(guān)代碼,主要有順序表的輸出、插入和刪除數(shù)據(jù)等,感興趣的小伙伴可以了解一下
    2022-10-10
  • C++之構(gòu)造函數(shù)默認(rèn)值設(shè)置方式

    C++之構(gòu)造函數(shù)默認(rèn)值設(shè)置方式

    這篇文章主要介紹了C++之構(gòu)造函數(shù)默認(rèn)值設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C++list的模擬實(shí)現(xiàn)

    C++list的模擬實(shí)現(xiàn)

    list是數(shù)據(jù)結(jié)構(gòu)中的鏈表,在C++的STL中,有l(wèi)ist的模板,STL中的list的結(jié)構(gòu)是帶頭雙向循環(huán)鏈表,當(dāng)然STL中還有一個(gè)forward_list的鏈表,這個(gè)鏈表是一個(gè)帶頭的單鏈表。為了更好的理解list,我們來對其進(jìn)行模擬實(shí)現(xiàn)。,需要的朋友可以參考
    2023-04-04
  • char str[] 與 char *str的區(qū)別詳細(xì)解析

    char str[] 與 char *str的區(qū)別詳細(xì)解析

    以下是對char str[]與char *str的區(qū)別進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下
    2013-09-09
  • OpenCV識別提取圖像中的水平線與垂直線

    OpenCV識別提取圖像中的水平線與垂直線

    這篇文章主要為大家詳細(xì)介紹了OpenCV識別提取圖像中的水平線與垂直線,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • 基于c++ ege圖形庫實(shí)現(xiàn)五子棋游戲

    基于c++ ege圖形庫實(shí)現(xiàn)五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了基于c++ ege圖形庫實(shí)現(xiàn)五子棋游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12

最新評論