程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> gSOAP MTOM,gsoapmtom

gSOAP MTOM,gsoapmtom

編輯:C++入門知識

gSOAP MTOM,gsoapmtom


前言

需要准備的知識:wsdl,soap,gSOAP,C++,fidder。

第一節 使用說明

MTOM(Message Transmission Optimization Mechanism)是一種新的(相對MIME、DIME)的SOAP消息傳輸附件的格式。MTOM附件本質上是在SOAP body標簽中引用的標准MIME附件,可以不用MIME附件而是用DIME附件。

MTOM在SOAP 1.2中實現,同時是用XOP命名空間。XOP Include元素xop:include(在SOAP body標簽中)用來引用附件(可以又多個附件)。

由於用MTOM方式強制規定SOAP 消息的body需要引用附件,GSoap是用類似DIME的實現方式實現MTOM和MIME的二進制附件的序列化和反序列化。這個二進制結構事前在 import/xop.h 文件中定義:

 

//gsoap xop schema import: http://www.w3.org/2004/08/xop/include
struct _xop__Include
{
unsigned char *__ptr;
int __size;
char *id;
char *type;
char *options;
};
typedef struct _xop__Include _xop__Include;

除了 id,type 還有兩個選項__ptr、__size可用。發送和接受MTOPM XOP附件的過程是完全自動的。id 關聯附件(典型的內容標識為CID或UUID)。當 id 為空=NULL時Gsoap會分配一個唯一的CID。type 字段指明二進制數據的MIME類型,同時可選選項可以用來傳輸附件的附加說明。結構體的字段聲明順序時敏感的(也就是結構的變量聲明順序不能變化).

 

可以聲明自己的數據結構體包含 xop.h MTOM的附件定義,例如:

 

#import ïmport/soap12.h"
/* alternatively, without the import above, use:
//gsoap SOAP-ENV schema namespace: http://www.w3.org/2003/05/soap-envelope
//gsoap SOAP-ENC schema namespace: http://www.w3.org/2003/05/soap-encoding
*/
#import ïmport/xop.h"
#import ïmport/xmime5.h"
//gsoap x schema namespace: http://my.first.mtom.net
struct x__myData
{
   _xop__Include xop__Include; // attachment
   @char *xmime5__contentType; // and its contentType
};
int x__myMTOMtest(struct x__myData *in, struct x__myData *out);

如上所示,在MTOM和DIME的附件在gSOAP的頭文件定義中除了MTOM附件必須時SOAP 1.2 和是用 xop__Include 元素外,沒有任何區別。

當 x_myData 實例序列化時,idtype 字段都不能為NULL,gSOAP的soap結構內容的標識為 SOAP_ENC_MTOM 時附件就會以 MTOM MIME附件方式傳輸。

 

struct soap *soap = soap_new1(SOAP_ENC_MTOM);

不設置這個標識附加將以 DIME 的方式傳輸。

如果你目前的客戶端和服務都是基於非流 DIME 附件使用SOAP正文引用機制(因此,沒有使用soap_set_dime_attachment函數)或純base64二進制XML數據元素,很容易采用MTOM通過重命名xop__Include和使用的二進制類型 SOAP_ENC_MTOM 標識與SOAP 1.2名稱空間。

 

第二節 流動式接收MTOM/MIME

流動式接收MTOM/MIME是用回調函數的方式實現附件傳輸期間的數據抓取和存儲。三個回調函數實現流動式接收MTOM/MIME的輸出(寫),三個回調函數實現流動式接收MTOM/MIME的輸入(讀)。

如下是輸入(讀取)附件的三個回調函數:

 

void *(*soap.fmimereadopen)(struct soap *soap, void *handle,const char *id, const char *type, const char *description)

 

size_t (*soap.fmimeread)(struct soap *soap, void *handle, char *buf, size_t len)

 

void(*soap.fmimereadclose)(struct soap *soap, void *handle)

 

如下是輸出(寫入)附加的三個回調函數:

 

void *(*soap.fmimewriteopen)(struct soap *soap, void *handle,const char *id, const char *type, const char *description,enum soap_mime_encoding encoding)

 

int (*soap.fmimewrite)(struct soap *soap, void *handle,const char *buf, size_t len)

 

void(*soap.fmimewriteclose)(struct soap *soap, void *handle)

此外,一個void *user字段結構soap數據結構可以將用戶定義的數據傳遞給回調函數。通過這種方式,您可以設置soap。用戶指向應用程序數據的回調需要,例如一個文件名。

 

下面的例子說明了客戶端初始化一個圖像附件結構流文件為MTOM附件沒有HTTP分塊:

 

int main()
{
struct soap soap;
struct xsd__base64Binary image;
   FILE *fd;
struct stat sb;
   soap_init1(&soap, SOAP_ENC_MTOM); // mandatory to enable MTOM
if (!fstat(fileno(fd), &sb) && sb.st_size > 0)
   { // because we can get the length of the file, we can stream it without chunking
      soap.fmimereadopen = mime_read_open;
      soap.fmimereadclose = mime_read_close;
      soap.fmimeread = mime_read;
      image.__ptr = (unsigned char*)fd; // must set to non-NULL (this is our fd handle which we need in the callbacks)
      image.__size = sb.st_size; // must set size
   }
else
   { // don't know the size, so buffer it
      size_t i;
int c;
      image.__ptr = (unsigned char*)soap_malloc(&soap, MAX_FILE_SIZE);
for (i = 0; i < MAX_FILE_SIZE; i++)
      {
if ((c = fgetc(fd)) == EOF)
break;
         image.__ptr[i] = c;
      }
      fclose(fd);
      image.__size = i;
   }
   image.type = "image/jpeg"; // MIME type
   image.options = "This is my picture"; // description of object
   soap_call_ns__method(&soap, ...);
   ...
}
void *mime_read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *description)
{ return handle;
}
void mime_read_close(struct soap *soap, void *handle)
{ fclose((FILE*)handle);
}
size_t mime_read(struct soap *soap, void *handle, char *buf, size_t len)
{ return fread(buf, 1, len, (FILE*)handle);
}

 

面的例子說明了MTOM / MIME的流由一個客戶端存儲在一個文件中:

 

int main()
{ struct soap soap;
   soap_init(&soap);
   soap.fmimewriteopen = mime_write_open;
   soap.fmimewriteclose = mime_write_close;
   soap.fmimewrite = mime_write;
   soap_call_ns__method(&soap, ...);
   ...
}
void *mime_write_open(struct soap *soap, const char *id, const char *type, const char *description, enum soap_mime_encoding encoding)
{
   FILE *handle = fopen("somefile", "wb");
   // We ignore the MIME content transfer encoding here, but should check
if (!handle)
   {
      soap->error = SOAP_EOF;
      soap->errnum = errno; // get reason
   }
return (void*)handle;
}
void mime_write_close(struct soap *soap, void *handle)
{ fclose((FILE*)handle);
}
int mime_write(struct soap *soap, void *handle, const char *buf, size_t len)
{
   size_t nwritten;
while (len)
   {
      nwritten = fwrite(buf, 1, len, (FILE*)handle);
if (!nwritten)
      {
         soap->errnum = errno; // get reason
return SOAP_EOF;
      }
      len -= nwritten;
      buf += nwritten;
   }
return SOAP_OK;
}

 

服務器端的文件管理同樣取決與回調函數的實現,如下是gSOAP提供的例子程序 mtom-stream 的服務端寫入的代碼

 

void *mime_server_write_open(struct soap *soap, void *unused_handle, const char *id, const char *type, const char *description, enum soap_mime_encoding encoding)
{
    /* Note: the 'unused_handle' is always NULL */
    /* Return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment */
    const char *file;
    struct mime_server_handle *handle = (struct mime_server_handle *)soap_malloc(soap, sizeof(struct mime_server_handle));
    if (!handle)
    { soap->error = SOAP_EOM;
        return NULL;
    }
    /* Create a new file */
   file = tempnam(TMPDIR, "data");

    /* The file name is also the key */
    handle->key = soap_strdup(soap, file);
    handle->fd = fopen(file, "wb");
    free((void*)file);
    if (!handle->fd)
    { soap->error = soap_sender_fault(soap, "Cannot save data to file", handle->key);
        soap->errnum = errno; /* get reason */
        return NULL;
    }
    fprintf(stderr, "Saving file %s type %s\n", handle->key, type?type:"");
    return (void*)handle;
}

   如上紅色的代碼使用 C 函數tempnam產生了一個臨時文件名用於保存附件,在真實的實現中可以根據MIME類型對附件進行分類管理。

第三節 使用SoapUI測試MTOM

如下圖在Attachments中添加若干附件,在soap請求的中的 xop:include 的屬性href中通過 cid 引用附件,

   

請求的結果為:

如上對的例子是以MTOM方式請求,返回的結果是base64編碼的二進制格式。同樣可以使用base64編碼的消息獲取MTOM方式的附件消息格式,如下:

 

第四節 用fidder獲得SoapUI報文

用Fidder獲取SoapUI的報文需要用的兩個軟甲的代理功能。

4.1 SoapUI設置

   step 1: 打開菜單 File--->Preferences

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved