2018年6月29日 星期五

[C/C++] 使用Gsoap產生Server/Client程式碼

Gsoap  最終目的即產生Server/Client的程式碼,其中:

  • Server Files Contains : 
    • soapStub.h
    • soapH.h
    • soapC.cpp
    • {soap.h}.nsmap
    • {soap.h}{service_name}Service.cpp
    • {soap.h}{service_name}Service.h
    • {service_name}.wsdl
  • Client Files Contains : 
    • soapStub.h
    • soapH.h
    • soapC.cpp
    • soapClient.cpp
    • {service_name}.wsdl

產生Server/Client的方法如下:
第一步:定義 soap.h,範例如下:

* 注意:註解的定義是必要的
//gsoap ns2  service name:  soap
//gsoap ns2  service style: rpc
//gsoap ns2  service encoding:  encoded
//gsoap ns2  service namespace: http://www.ateam.cn
//gsoap ns2  schema namespace:  urn:proscan

class ResponseBase {
    char status;
    char *message;
};

class NtpResponse : public ResponseBase {
    char *dateTime;
    char *host;
};

int ns2__getNtpHost(
    NtpResponse   &result ///< Output parameter, : unqualified name as per RPC encoding
);

int ns2__setNtpHost(
    char *name,
    char *host,
    NtpResponse &result
);

第二步:根據soap.h檔,產生Server/Client所需的程式,語法如下:

  • Server Comnad:
    #soapcpp2 -jSL soap.h
  • Client Command :
    #soapcpp2 -jCL soap.h

第三步:撰寫主程式
  • Server : main.cpp
    #include <pthread.h>
    #include "soap.nsmap"
    #include "soapsoapService.h"
    #include "strtool.h"

    using std::string;
    using std::vector;
    using std::cout;
    using std::endl;

    #define WSDL_PATH "proscan.wsdl"
    int rep_wsdl(struct soap *soap, string path, string params)
    {
      FILE *fd = NULL;

      fd = fopen(WSDL_PATH, "rb");
      if (!fd)
        return 404;

      soap->http_content = "text/xml";
      soap_response(soap, SOAP_FILE);

      for (;;)
      {
        size_t r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd);
        if (!r)
          break;
        if (soap_send_raw(soap, soap->tmpbuf, r))
          break;
      }

      fclose(fd);
      soap_end_send(soap);
      return SOAP_OK;
    }

    int http_get(struct soap *soap)
    {
      vector<string> vt;
      strtool::split(soap->path, vt, "?");

      if ( vt[0].compare("/proscan") == 0 ) {
        if ( vt.size() == 2 && vt[1].compare("wsdl") == 0 ) {
          return rep_wsdl(soap, vt[0] , vt[1]);
        }
      }
      return SOAP_GET_METHOD;
    }

    int main(int argc, char **argv)
    {
      struct soap soap;
      int server_port = 8080;
      //proscanService proscan(SOAP_XML_INDENT);
      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();
    }
  • Client : main.cpp
    準備中

第四步:編譯程式碼
* 注意:編譯前需從原始碼裡複製此兩檔案 : stdsoap2.cpp, stdsoap2.h
  • Server Command
    #g++ -o ${target} main.cpp soap.cpp soapsoapService.cpp main.cpp soapC.cpp stdsoap2.cpp -lpthread

  • Client Command
    #g++ -o ${target} soap.cpp soapC.cpp soapClient.cpp stdsoap2.cpp


備註:
除了自行編寫soap.h之外,gsoap還提供將wsdl轉成soap.h的方法,語法如下:

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


Reference:
[1] https://www.genivia.com/dev.html#what

沒有留言:

張貼留言