2016年9月1日 星期四

[C++] 使用 Gsoap 開發 Web Services

    GSOAP是一套非常強大的SOAP Service軟體,只需要撰寫好wsdl或者 .h的定義欓,在根據不同參數就可以產生出相對代碼出來,然後再針對所要提供的服務進行實作即可。經過我幾次的測試,個人認為編輯.h欓來產生wsdl與相對應的程式碼最容易了解。以下則以該方向進行介紹。

  • 下載最新版 gsop並安裝

    #apt-get install byacc flex bison autoconf libssl-dev
    #./configure
    #make
    #make install
  • 編輯 soap.h

    #ifndef SOAP_H
    #define SOAP_H
    //gsoap ns2  service name:      soap
    //gsoap ns2  service style:     rpc
    //gsoap ns2  service encoding:  encoded
    //gsoap ns2  service namespace: http://github.com/linuxxunil
    //gsoap ns2  schema namespace:  urn:soap

    class ResponseBase {
            bool status;    // Y,N
            std::string message;
            std::string dateTime;
    };


    class Data {
            std::string dateTime;
            std::string content;
    };

    class DataArray {
            int __size;
            Data *data;
    };

    // 定義getData的回傳結構
    class DataRep : protected ResponseBase {
            int quantity;
            DataArray dataArray;
    };

    // 定義getData的回傳函數,注意:ns2__ 是gsop識別符號
    int ns2__getData(
            std::string name,
            DataRep &result
    );


    #endif

  • 使用soapcpp2產生soap service相關檔案
    #soapcpp2 -jSL soap.h

    -j    generate C++ service proxies and objects that share a soap struct
    -S   generate server-side code only
    -L   don't generate soapClientLib/soapServerLib

    Note :
    1. soap.wsdl  - wsdl File

    2. 以下四個檔案為Http溝通的格式,其中req代表Request,res代表Response。可以使用POSTMan進行測試。
    soap.getSystemTime.req.xml
    soap.getSystemTime.res.xml
    soap.getData.req.xml
    soap.getData.res.xm

    3. soapsoapService.h - soap的結構 ,

  • 實作 soap.cpp (對應soap.h)
    #include "soapsoapService.h" 
    int soapService::getData(std::string name, DataRep &result) {
        // soapService 參考soapsoapService.h 裡的物件名稱
        // getSystemTime 實作的函數名稱
        // std::string name 傳進參數
        // DataRep &result 輸出結果

        std::string date[] = {"16:00:00","17:00:00","18:00:00"}; //測試資料
        std::string content[] = {"test1","test2","test3"}; //測試資料

        std::cout << "name : " << name << std::endl;
        result.status = true;
        result.message = "OK";
        result.dateTime = "2016/09/01 16:14:00";
        result.dataArray.__size = 3; //給予該陣列的大小
        result.quantity = result.dataArray.__size ;
        if ( result.dataArray.__size > 0 ) {
            result.dataArray.data = new Data[result.dataArray.__size];
            for ( int i=0 ; i<result.dataArray.__size; i++ ) {
                result.dataArray.data[i].dateTime = date[i];
                result.dataArray.data[i].content = content[i];
            }
        }
        return SOAP_OK;
    }
  • Main 主程式
    ...(省略)
    int main(int argc, char **argv)
    {
      struct soap soap;
      int server_port = 8080;

      soap.fget = http_get;
      soap.bind_flags = SO_REUSEADDR;
      soap.send_timeout = 60; // 60 seconds
      soap.recv_timeout = 60; // 60 seconds
      soap.accept_timeout = 3600; // server stops after 1 hour of inactivity
      soap.max_keep_alive = 100; // max keep-alive sequence
      soapService soapService(&soap);


      if ( argc > 2 ) {
        server_port = atoi(argv[1]);
      }

      if (soapService.run(server_port) != SOAP_OK) {
        soapService.soap_stream_fault(std::cerr);
      }
      soapService.destroy();
    }
  • Compiler
    a. 從原始Source複製 stdsoap2.h 和stdsoap2.cpp  (路徑 : .../gsoap-2.8/gsoap/ )
    b. g++ -o soap_test soap.cpp soapsoapService.cpp  main.cpp soapC.cpp stdsoap2.cpp -lpthread
  • 測試
    #./soap_test
    POSTMan 輸入參數


    POSTMan 輸出結果




Reference :
[1] GSOAP Offical
[2] GSOAP Source File
[3] https://github.com/linuxxunil/gsoapExample

沒有留言:

張貼留言