gSOAP MTOM
前言
需要准备的知识:wsdl,soap,gSOAP,C++,fidder。
首先介绍几个相关的概念
1、MTOM基础概念
MTOM(Message Transmission Optimization Mechanism)消息优化传输机制。
它提出的模型适用于大量数据的交互情况。针对Base64编码情况带来的开销提出的解决方案。当数据量小的时候,SOAP依然使用XML进行消息的传递。
消息传输优化机制 (MTOM) 标准允许将消息中包含的大型数据元素外部化,并将其作为无任何特殊编码的二进制数据随消息一起传送。MTOM 消息会打包为多部分/相关 MIME 序列,放在SOAP 消息中一起传送。
但是在大量数据情况下,如果数据依然进行Base64编码,会带来33%的额外开销,这样的情况对于大量数据交换的情况是无法容忍的。MTOM 就是针对SOAP 消息传输的基础上提出的改进办法。对于大量数据的传递,不会进行进行Base64编码,而是直接以附件的二进制原始数据的形式封装在SOAP消息的 MIME 部分,进行传输。SOAP 消息通过指向随其发送的 MIME 部分来引用二进制内容,另外包括SOAP基本的XML 数据,这些还是Base64编码。因为此模型与简单邮件协议SMTP 模型基本一致。
MTOM通过简化大量数据的编码过程,从而提高数据的处理效率。因为SOAP消息等必要的信息,MTOM 也有一些必要的开销。MTOM仅在二进制数据元素的大小超过大约 1 KB 时,才能体现出其优势。
什么是BASE64编码、MTOM消息优化传输机制、MIME。这些对于我们理解MTOM消息优化传输机制问题非常的必要。
2、BASE64编码
BASE64编码 的原理很简单,其方法是,将输入数据流每次取6 bit(每bit代表1位二进制),不足6bit的补0,这样,每3个8位字节将编码为4个6位字节(3×8 → 4×6);不满4个字节的以“=”填充。其实这4个六位字节 仍然是8位,只不过高两位被设置为0。当一个字节只有6位有效时,它的取值空间为0 到 2的6次方减1 即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0~63)。
这样就可以将3个8位字节,转换为4个字节,这4个转换的字节都可以映射到字符中。也即数据都可以使用字符编码代替。 因为转换后的字符串要比原来的多一个字节,长1/3。因此编码后的数据长度增加到4/3倍。这里也是为什么使用SOAP消息效率比MTOM低的原因。因为 SOAP使用XML语言进行消息传递,XML是基于BASE64编码的语言。
3、MIME
MIME表示多用途Internet邮件扩允协议。MIME扩允了基本的面向文本的Internet邮件系统,以便可以在消息中包含二进制附件。MIME(Multipurpose Internet Mail Extentions),一般译作"多用途的网络邮件扩充协议"。顾名思义,它可以传送多媒体文件。 MIME (Multipurpose Internet Mail Extensions,多目的Internet邮件扩展)是创建用于电子邮件交换,网络文档,及企业网和Internet上的其他应用程序中的文件格式的规范。
第一节 使用说明
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 实例序列化时,id 和 type 字段都不能为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
step 2: 选择Proxy Setting选项卡进行如下设置:
4.2 Fidder设置
step 1: Tools-》 Options
step 2:打开选项卡 Connections
原理上就是SoapUI通过8888端口为代理对外发送请求,而Fidder监听8888端口的代理事件。如下为用Fidder截取的SoapUI发送的报文:
gSOAP MTOM的更多相关文章
- gsoap使用总结
WebService.soap.gsoap基本概念 WebService服务基本概念:就是一个应用程序,它向外界暴露出一个可以通过web进行调用的API,是分布式的服务组件.本质上就是要以标准的形式实 ...
- gsoap简介
gSoap是什么? 请进 官方网站 http://genivia.com/index.html 这里更直接 http://www.cs.fsu.edu/~engelen/soap.html 英语水平很 ...
- gsoap使用
一. 安装gsoap 下载地址:http://sourceforge.net/projects/gsoap2/files/ 解压安装:./configure --prefix=/usr/local/g ...
- gsoap设置超时
1.修改gsoap自动生成的代码才能进行超时设置(我这边访问web service的代码都是gsoap工具自动生成.根据wsdl接口) 2.找到生成的soapwwwsdlBindingProxy.cp ...
- MTOM以及在WCF中的应用
关于MTOM的基本概念 提到MTOM消息优化传输机制,通常的实验结果是使用MTOM传输数据会提高大约33%的性能. 消息传输优化机制 (MTOM) 标准允许将消息中包含的大型数据元素外部化,并将其作为 ...
- gsoap框架下的onvif程序流程分析
SOAP_FMAC5 int SOAP_FMAC6 soap_serve(struct soap *soap) { do { unsigned int k = soap->max_keep_al ...
- 基于gSOAP使用头文件的C语言版web service开发过程例子
基于gSOAP使用头文件的C语言版web service开发过程例子 一服务端 1 打开VS2005,创建一个工程,命名为calcServer. 2 添加一个头文件calc.h,编辑内容如下: 1// ...
- gSoap的 “error LNK2001: 无法解析的外部符号 _namespaces”解决方法
gSoap是C/C++开发webService服务第三方的公开类库. 出现上述错误是因为缺少必要的头文件导致的. 在用wsdl2h生成头文件的时候,一并生成了类似 xx.nsmap 的文件,这个文件实 ...
- 在Windows下用gSoap实现简单加法实例
实现一个简单的a+b程序,在服务器端写一个程序,里面包含了a+b的函数,然后通过客户端代码向其发送两个数字,在服务器运算得到结果返回给客户端显示出来. 1.在gSoap的官网上下载文件夹,本人的版本是 ...
随机推荐
- Bower是什么?
一.简介 Bower是一个客户端技术的软件包管理器,它可用于搜索.安装和卸载如JavaScript.HTML.CSS之类的网络资源.其它一些建立在Bower基础之上的开发工具,如YeoMan和Grun ...
- 考勤系统代码分析——主页布局easyui框架
考勤系统主页的布局用的是easyui的Layout控件 Layout:布局容器有5个区域:北.南.东.西和中间.中间区域面板是必须的,边缘的面板都是可选的.每个边缘区域面板都可以通过拖拽其边框改变大小 ...
- OpenCASCADE PCurve of Topological Face
OpenCASCADE PCurve of Topological Face eryar@163.com Abstract. OpenCASCADE provides a class BRepBuil ...
- MVC4做网站后台:用户管理 ——用户组补充
上次做完发现存在点问题. 1.是类型显示的为数字(如下图): 2.是不能根据类型进行查询. 首先做查询.easyui-datagrid可以添加toolbar. 在datagrid的data-optio ...
- c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖)
一. sizeof计算结构体 注:本机机器字长为64位 1.最普通的类和普通的继承 #include<iostream> using namespace std; class Parent ...
- JSONP详解
0.关于JSONP 什么的JSONP JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料.另一个解决这个问题的新方法是跨来源资源共享. ...
- VS2015 Enterprise 安装之惊险及收获
前言 园子早早的就有人安装了VS 2015,自己也按捺不住了,也要赶快尝尝鲜!结果在其安装过程中一个小小的问题却困扰了我一天,这其中多亏了dudu耐心的解答才得以顺利完成,如果你也遇见这个问题,看过这 ...
- 6-tips-for-managing-property-files-with-spring--转
原文地址:http://www.summa.com/blog/2009/04/20/6-tips-for-managing-property-files-with-spring What could ...
- C#中构造函数的作用
C#中构造函数的作用 共同点: 都是实例化对象,初始化数据的 默认构造是说所有的类都从祖先object那继承了空参的构造方法,你不写与写空参构造都存在,而有参数的构造一般是自己写的,写就有不写就没有, ...
- 用CSS制作带图标的按钮
先上一张效果图