主頁 > 後端開發 > C++中gSOAP的使用

C++中gSOAP的使用

2021-08-31 17:17:59 後端開發

目錄
  • SOAP簡介
  • gSOAP
    • 準備作業
    • 頭檔案
    • 構建客戶端應用程式
      • 生成soap原始碼
      • 建立客戶端專案
    • 構建服務端應用程式
      • 生成SOAP原始碼
      • 建立服務端專案
    • 列印報文
  • SOAP測驗
  • 專案原始碼

本文主要介紹C++中gSOAP的使用方法,附帶介紹SOAP協議的基礎知識,適用于第一次使用gSOAP的開發人員,gSOAP官網上的示例代碼存在一些錯誤,對初次接觸的人不太友好,本文是在官方示例calc++的基礎上進行了一些補充、改動,

SOAP簡介

SOAP 是一種簡單的基于 XML 的協議,它使應用程式通過 HTTP 來交換資訊,具體內容可以參考SOAP 教程,SOAP的本質是通過HTTP協議以XML格式進行資料互動,只不過這個XML格式的定義是大家公認的,

使用SOAP時需注意,SOAP的XML命名空間由于版本的不同可能存在差異(如soapevnSOAP-ENV),在呼叫SOAP服務前最好確認服務器的XML格式,

gSOAP

gSOAP 有商業版、開源版兩個版本,開源版使用GPLv2開源協議,支持多個作業系統,具體內容參考github或者官網

gSOAP提供了一組編譯工具(可以認為是代碼生成器)和一些庫檔案,簡化C/C++語言開發web服務或客戶端程式的作業,開發人員可以專注于實作應用程式的邏輯:

  • 編譯工具提供了一個SOAP/XML 關于C/C++ 語言的實作,能夠自動完成本地C或C++資料型別和XML資料結構之間的轉換,
  • 庫檔案提供了SOAP報文生成、HTTP協議通訊的實作,及相關的配套設施,用于最終的SOAP報文的生成、傳輸,

本文使用的庫檔案主要是以下幾個:

  • stdsoap2.h、stdsoap2.cpp:HTTP協議的實作、最終的SOAP報文生成,如果是C語言則使用stdsoap2.h、stdsoap2.c
  • typemap.dat: wsdl2h工具根據wsdl檔案生成頭檔案時需要此檔案,可以更改專案的xml命名空間(后面再細說)
  • threads.h:實作高性能的多執行緒服務器需要的檔案,可以并發處理請求,并且在服務操作變得耗時時不會阻塞其他客戶端請求

準備作業

先進入官網的下載頁面,然后選擇開源版本:

也可以直接點擊開源版本的官方下載鏈接或gsoap_2.8.117 提取碼: f78f,

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

命令列提示符視窗中,使用cd命令進入..\gsoap_2.8.117\gsoap-2.8\gsoap\bin\win64目錄:

注:后面需要把頭檔案、typemap.dat放到該程式目錄下,生成的檔案也在這里,

頭檔案

使用gSOAP的編譯工具生成代碼,需要一個定義API的頭檔案,此處使用官方示例中的calc.h頭檔案,對兩個數字進行加、減、乘、除或乘方運算:,
calc.h頭檔案可以通過wsdl2h工具自動生成(需要Web 服務的 WSDL檔案 ),運行的cmd命令如下:

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

也可以手動定義一個calc.h頭檔案,內容如下:

//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);

構建客戶端應用程式

客戶端應用程式在命令列中運行并使用命令列引數呼叫計算器 Web 服務來對兩個數字進行加、減、乘、除或乘方運算,

生成soap原始碼

為客戶端生成服務和資料系結介面:

soapcpp2 -j -r -CL calc.h

其中 option-j生成 C++ 代理類,option-r生成報告,option-CL僅生成客戶端,而沒有(未使用的)lib 檔案,

這會生成以下幾個檔案:

其中,xml檔案是SOAP報文的示例,便于后期的除錯,以add方法為例,

add方法的請求報文ns.add.req.xml內容如下:

<?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方法的回應報文ns.add.req.xml內容如下:

<?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>

建立客戶端專案

建立一個C++的控制臺應用專案,引入上面生成的幾個檔案:

  • soapStub.h: 沒有注釋的純 C/C++ 頭檔案語法的規范副本,
  • soapH.h:宣告 XML 序列化程式,
  • soapC.cpp: 實作 XML 序列化程式,
  • soapProxy.h: 定義客戶端 XML 服務 API 類Proxy,
  • soapProxy.cpp: 實作客戶端 XML 服務 API 類Proxy,
  • calc.nsmap: XML 命名空間系結表到 #include,

還需要引入gSOAP解壓目錄下的stdsoap2.hstdsoap2.cpp檔案,

為方便除錯,客戶端程式示例改為固定引數呼叫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;
}

構建服務端應用程式

實作一個獨立的迭代服務器,它接受主機埠上的傳入請求,支持多執行緒,可以并發處理請求,并且在服務操作變得耗時時不會阻塞其他客戶端請求,

生成SOAP原始碼

為服務器端生成服務和資料系結介面:

soapcpp2 -j -r -SL calc.h

其中 option-j生成 C++ 服務類,option-r生成報告,option-SL僅生成服務器端,而沒有(未使用的)lib 檔案,

生成的檔案和客戶端的檔案名稱一樣,只是內容不同,

建立服務端專案

建立一個C++的控制臺應用專案,引入的生成檔案和客戶端的相同,為了支持多執行緒,需要引入檔案threads.h
服務端代碼如下:

#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;
}

列印報文

在實際除錯中,需要確定SOAP協議程序中具體的報文,只需要改動stdsoap2.cpp原始碼即可,參考gsoap報文列印,實作保存最后一次報文到特定的檔案,

stdsoap2.h頭檔案include下添加fstream,內容如下:

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

soap_begin_recv函式開始處添加以下代碼:

//發送完請求報文 獲取請求報文資訊(作為客戶端的時候)
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函式開始處添加以下代碼:

//接收完應答報文 獲取應答報文資訊(作為客戶端的時候)
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函式結尾處(return前)添加以下代碼:

//請求報文(作為服務端的時候)
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函式結尾處(return前)添加以下代碼:

//應答報文(作為服務端的時候)
std::string res_data;
res_data.assign(s, n);
std::ofstream  outfile;
outfile.open("res_data.txt");
outfile << res_data;
outfile.close();

注:客戶端可以一直列印報文,服務端只能在Debug運行時才會列印報文,應該有其它方法可以解決,

SOAP測驗

運行上面的服務器、客戶端專案,可以看到運行API呼叫結果,也可以使用SoapUI進行測驗,

進入官網的下載鏈接:https://www.soapui.org/downloads/soapui/,下載開源版本并安裝,

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

展開左側的專案,雙擊“Request”,開始進行測驗:

專案原始碼

  • SoapTest 提取碼: x4yr

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295931.html

標籤:C++

上一篇:【C++ Primer Plus】編程練習答案——第7章

下一篇:C語言 二維陣列遍歷 - C語言零基礎入門教程

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more