gSOAP 學習


由於工作調動關係,需要了解 gSOAP 的使用,寫個文章記錄一下學習的心得,免得以後忘記。

安裝

由於本人使用的是 Mac OS 系統,故以 Mac OS 爲例說明如何安裝 gSOAP。

1)下載 gSOAP

可以在 https://sourceforge.net/projects/gsoap2 下載最新版本的 gSOAP。

2)安裝 flex, bison, openssl

可以使用brew install進行安裝:

brew install flex bison openssl
  • 1

3)編譯安裝 gSOAP

解壓上面下載的 gSOAP,然後執行下面的命令:

cd gsoap-2.8
./configure --with-openssl=/usr/local/opt/openssl
make
sudo make install
  • 1
  • 2
  • 3
  • 4

安裝完成,會出現以下的提示:

安裝中如果出現 fatal error: 'openssl/bio.h' file not found 的錯誤,可以通過嘗試重新安裝 openssl 和使用最新的 gsoap-2.8 版本的方法來解決,具體解決辦法也可以 google 一下。

其他平臺的安裝教程可以參考官方文檔:https://www.genivia.com/downloads.html

gSOAP 工具

gSOAP 提供了兩個工具來方便開發人員使用 C/C++ 語言快速開發Web 服務應用,通過 gSOAP 提供的這兩個工具,開發人員可以快速生成服務端與客戶端代碼框架,接下來開發人員只需要實現具體的接口函數即可。

wsdl2h

wsdl2h 工具根據 WSDL 文件生成 C/C++ .h 頭文件。
WSDL(Web Service Description Language)即 Web 服務描述語言,它使用 XML 來對 Web 服務進行描述。
wsdl2h 的用法:

wsdl2h -o 頭文件名 WSDL文件名或URL
  • 1

例如:

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

wsdl2h 根據 URL 指定的 WSDL 生成calc.h頭文件。calc.h對 Web 服務接口進行定義。

wsdl2h 支持額外的參數:

  • -s 生成的頭文件不使用 STL
  • -o 文件名,指定輸出頭文件的名稱
  • -c 產生純 C 代碼,否則是 C++ 代碼
  • -t 文件名,指定 type map 文件,默認是 typemap.dat

soapcpp2

soapcpp2 工具則從上面生成的頭文件生成 SOAP 服務端和客戶端框架代碼。例如對於上面的cacl.h,使用 soapcpp2 命令:

soapcpp2 -i -Iimport calc.h
  • 1

soapcpp2 也支持額外的參數:

  • -i 生成 C++ 包裝類,客戶端爲 xxxProxy.h(.cpp),服務端爲xxxService.h(.cpp)
  • -I 指定 import 的路徑,比如需要引入stlvector.h文件來支持 STL vector 的序列化
  • -C 僅生成客戶端代碼
  • -S 僅生成服務端代碼
  • -c 產生純 C 代碼,否則是 C++ 代碼
  • -x 不要產生 XML 示例文件
  • -L 不要產生soapClientLib.csoapServerLib.c文件

例子

gSOAP 中包含了大量的例子以便讓開發人員快速瞭解如何使用 gSOAP 開發 Web 服務。
我們以 gSOAP 的 samples 目錄下的 calc++ 的代碼爲例,說明如何使用 gSOAP 來編寫客戶端和的服務端代碼。

calc++ 目錄已經包含了 calc.h 頭文件,這個頭文件跟上面我們使用 wsdl2h 生成的 calc.h 頭文件並不完全相同,爲了實驗的方便,我們使用 calc++ 目錄的calc.h 頭文件進行實驗。

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

然後,我們使用 soapcpp2 工具來生成客戶端和服務端的框架代碼:

soapcpp2 -i -Iimport calc.h
  • 1

客戶端代碼

calcclient.c++ 代碼:

#include "soapcalcProxy.h"
#include "calc.nsmap"

const char server[] = "http://127.0.0.1:8080";

int main(int argc, char **argv)
{ if (argc < 4)
  { fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n");
    exit(0);
  }
  double a, b, result;
  a = strtod(argv[2], NULL);
  b = strtod(argv[3], NULL);
  calcProxy calc;
  calc.soap_endpoint = server;
  switch (*argv[1])
  { 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(0);
  }
  if (calc.error)
    calc.soap_stream_fault(std::cerr);
  else
    printf("result = %g\n", result);
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

由於代碼使用 STL,爲了順利編譯通過,需要將 gSOAP 中的stdsoap2.cppstdsoap2.h文件拷貝到客戶端和服務端代碼所在的目錄。
改寫好客戶端代碼後,使用 g++ 進行編譯:

g++ -o calcclient calcclient.cpp soapC.cpp soapcalcProxy.cpp stdsoap2.cpp
  • 1

編譯順利通過。

服務端代碼

calcserver.cpp代碼如下,其中可以指定服務端的端口號:

#include "soapcalcService.h"
#include "calc.nsmap"

int main(int argc, char **argv)
{ calcService calc;
  if (argc < 2)
    calc.serve();   /* serve as CGI application */
  else
  { int port = atoi(argv[1]);
    if (!port)
    { fprintf(stderr, "Usage: calcserver++ <port>\n");
      exit(0);
    }
    /* run iterative server on port until fatal error */
    if (calc.run(port))
    { calc.soap_stream_fault(std::cerr);
      exit(-1);
    }
  }
  return 0;
} 

int calcService::add(double a, double b, double *result)
{ *result = a + b;
  return SOAP_OK;
} 

int calcService::sub(double a, double b, double *result)
{ *result = a - b;
  return SOAP_OK;
} 

int calcService::mul(double a, double b, double *result)
{ *result = a * b;
  return SOAP_OK;
} 

int calcService::div(double a, double b, double *result)
{ if (b)
    *result = a / b;
  else
  { char *s = (char*)soap_malloc(this, 1024);
    (SOAP_SNPRINTF(s, 1024, 100), "<error xmlns=\"http://tempuri.org/\">Can't divide %f by %f</error>", a, b);
    return soap_senderfault("Division by zero", s);
  }
  return SOAP_OK;
} 

int calcService::pow(double a, double b, double *result)
{ *result = ::pow(a, b);
  if (soap_errno == EDOM)   /* soap_errno is like errno, but compatible with Win32 */
  { char *s = (char*)soap_malloc(this, 1024);
    (SOAP_SNPRINTF(s, 1024, 100), "<error xmlns=\"http://tempuri.org/\">Can't take power of %f to %f</error>", a, b);
    return soap_senderfault("Power function domain error", s);
  }
  return SOAP_OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

然後使用 g++ 來對服務端代碼進行編譯:

g++ -o calcserver calcserver.cpp soapC.cpp soapcalcService.cpp stdsoap2.cpp
  • 1

編譯同樣順利通過。

測試

運行上面編譯好的calcservercalcclient可執行文件
來對 Web 服務進行測試,測試結果如下:

參考資料


  1. https://www.cs.fsu.edu/~engelen/soapdoc2.html
  2. https://www.genivia.com/downloads.html
  3. https://www.genivia.com/dev.html
  4. http://blog.csdn.net/yangjun1115/article/details/29360389
  5. https://www.cs.fsu.edu/~engelen/calc.html
  6. http://commandos.blog.51cto.com/154976/130652
  7. http://www.cppblog.com/qiujian5628/archive/2008/10/11/54019.html
  8. http://blog.sina.com.cn/s/blog_5ee9235c0100de3g.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章