MTOM消息优化传输机制主要应用于大量数据的传输,很多文章中也直接得出结论:使用MTOM文件传输效率高。为什么MTOM的数据传输效率会比别的方式要高?MTOM真的如此完美吗,它有什么不足?什么情况下使用MTOM?这些疑问,本文WSE3.0构建Web服务安全系列文章的第4节:MTOM消息优化传输机制和文件上传、下载--将为您一一解答。本节结构为1.MTOM基础概念2.WSE3.0工具配置MTOM3.代码实现与分析4.总结。最后附上实现代码供大家参考。
WSE3.0中引入MTOM机制,给我们借助WSE框架实现大量数据的交互带来显著的益处。在WSE 3.0中,我们可以使用MTOM用于服务器端和客户端传递消息,另外的好处就是,WSE 3.0M允我们在传递大数据量时使用WSE 3.0消息层的安全性机制,借助WSE3.0的安全框架,我们不仅可以验证用户的合法性,还可以对消息进行加密,不仅能够保证数据的安全,还可以实现大数据量的高效传输。
1.【MTOM基础概念】
提到MTOM消息优化传输机制,通常的实验结果是使用MTOM传输数据会提高大约33%的性能。 消息传输优化机制 (MTOM) 标准允许将消息中包含的大型数据元素外部化,并将其作为无任何特殊编码的二进制数据随消息一起传送。MTOM 消息会打包为多部分/相关 MIME 序列,放在SOAP 消息中一起传送。
我们需要了解一些相关的概念。什么是BASE64编码、MTOM消息优化传输机制、MIME。这些对于我们理解MTOM消息优化传输机制问题非常的必要。下面就来做下介绍。
1.1【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编码的语言。
1.2【MIME】
MIME表示多用途Internet邮件扩允协议。MIME扩允了基本的面向文本的Internet邮件系统,以便可以在消息中包含二进制附件。MIME(Multipurpose Internet Mail Extentions),一般译作"多用途的网络邮件扩充协议"。顾名思义,它可以传送多媒体文件。 MIME (Multipurpose Internet Mail Extensions,多目的Internet邮件扩展)是创建用于电子邮件交换,网络文档,及企业网和Internet上的其他应用程序中的文件格式的规范。
1.3【MTOM消息优化传输】
MTOM 全称Message Transmission Optimization Mechanism,即消息传输优化机制。它提出的模型适用于大量数据的交互情况。针对Base64编码情况带来的开销提出的解决方案。当数据量小的时候,SOAP依然使用XML进行消息的传递。
但是在大量数据情况下,如果数据依然进行Base64编码,会带来33%的额外开销,这样的情况对于大量数据交换的情况是无法容忍的。MTOM 就是针对SOAP 消息传输的基础上提出的改进办法。对于大量数据的传递,不会进行进行Base64编码,而是直接以附件的二进制原始数据的形式封装在SOAP消息的MIME 部分,进行传输。SOAP 消息通过指向随其发送的 MIME 部分来引用二进制内容,另外包括SOAP基本的XML 数据,这些还是Base64编码。因为此模型与简单邮件协议SMTP 模型基本一致。
MTOM通过简化大量数据的编码过程,从而提高数据的处理效率。因为SOAP消息等必要的信息,MTOM 也有一些必要的开销。MTOM仅在二进制数据元素的大小超过大约 1 KB 时,才能体现出其优势。
2.【WSE3.0工具配置MTOM】
在WSE3.0项目中使用MTOM消息传输优化机制非常的方便,我们可以使用WSE 3.0配置工具分别为Web 服务和Client客户端设置启用MTOM,生成相应的策略文件,WSE3.0机制会根据策略对消息传输使用MTOM(也可以通过代码实现) 。
数据使用字节流byte[]数组在客户端和服务端进行传输,简单的例子就是消息的交互和文件的上传和下载操作。本次配置基本介绍的情况也是借助WSE3.0的安全机制实现文件的安全传输。
2.1首先使用WSE 3.0配置工具设置服务端消息传输策略。如图:
客户端设置为on,要求客户端使用MTOM机制进行数据传输。服务端设置为Optional,表示可选,服务端既支持MTOM又可以不支持MTOM编码的消息。适用性强。
此种情况即服务端会根据客户端的请求类型来决定是否启用MTOM机制进行数据传递.如果客户端适用MTOM编码,则服务会启用MTOM处理消息。如果设置为Always,服务端会一直使用MTOM机制进行消息的传递。一般不推荐使用这个方式。OFF即一直不使用MTOM机制进行消息传递。64为最大附加二进制文件的个数。最后表示需要首先使用SOAP消息封装。
The optional
mode is the default settings. In this mode the WSE processes the incoming SOAP messages whether or not they are MTOM
encoded. This gives much more flexibility to web services that are not only dealing with large amount of data. With optional the client is the one who decide whether to use MTOM
or not, if the client application request to use MTOM
the web service will use MTOM
.
In always
mode all incoming and outgoing SOAP messages must be MTOM
encoded. When a SOAP request is received that is not encoded using MTOM
, an HTTP error 415: "Media unsupported" is returned to the sender. This option is ideal for Web Services that only deal with large amount of data.
In never
mode all incoming SOAP messages must not be MTOM
encoded. When a SOAP request is received that is encoded using MTOM
, an HTTP error 415: "Media unsupported" is returned to the sender. That means the client application should never use MTOM
.
对应的配置文件为:
<messaging>
<mtom serverMode="optional" clientMode="On" />
</messaging>
<mtom serverMode="optional" clientMode="On" />
</messaging>
2.2客户端的设置与服务端类似:
客户端配置文件的代码如下:
<messaging>
<mtom clientMode="On" serverMode="optional" />
</messaging>
<mtom clientMode="On" serverMode="optional" />
</messaging>
3.【代码实现与分析】
进行完毕配置以后我们来具体进入代码的开发阶段。这里给出了使用MTOM上传照片的例子,一个使用了证书加密图片上传。先给出服务端的实现,包括两个服务类:WSE3MTOMService和WSE3MTOMSecureService。方法都是二进制字节数据流的传递。
3.1WSE3MTOMService直接实现基于MTOM机制的图片上传和下载方法,具体实现如下:
//WSE 3.0 Samples中的MTOM示例演示了:不加密上传、下载文件、
[WebService(Namespace = "http://www.cnblogs.com/frank_xl/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WSE3MTOMService : System.Web.Services.WebService
{
public WSE3MTOMService()
{
}
[WebService(Namespace = "http://www.cnblogs.com/frank_xl/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WSE3MTOMService : System.Web.Services.WebService
{
public WSE3MTOMService()
{
}
//此方法返回不加密的字节数组,下载文件
[WebMethod]
public byte[] DownLoadFile(string fileName)
{
byte[] file = new byte[1024];
String filePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\" + fileName;
file = File.ReadAllBytes(filePath);
return file;
}
//上传文件,传回2进制数据
[WebMethod]
public void UpLoadFile(byte[] file)
{
String filePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\" + "FrankXuLei.gif";
if (File.Exists(filePath))
File.Delete(filePath);
File.WriteAllBytes(filePath, file);
}
}
[WebMethod]
public byte[] DownLoadFile(string fileName)
{
byte[] file = new byte[1024];
String filePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\" + fileName;
file = File.ReadAllBytes(filePath);
return file;
}
//上传文件,传回2进制数据
[WebMethod]
public void UpLoadFile(byte[] file)
{
String filePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\" + "FrankXuLei.gif";
if (File.Exists(filePath))
File.Delete(filePath);
File.WriteAllBytes(filePath, file);
}
}
3.2WSE3MTOMSecureService定义了一个文件下载的方法。具体如下:
//WSE 3.0 Samples中的MTOM示例演示了:加密上传、下载文件、
[WebService(Namespace = "http://www.cnblogs.com/frank_xl/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
//Returns binary data secured via the ServerPolicy in the wse3policyCache.config policy file
[Policy("ServerPolicy")]
public class WSE3MTOMSecureService : System.Web.Services.WebService
{
public WSE3MTOMSecureService()
{
}
[WebService(Namespace = "http://www.cnblogs.com/frank_xl/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
//Returns binary data secured via the ServerPolicy in the wse3policyCache.config policy file
[Policy("ServerPolicy")]
public class WSE3MTOMSecureService : System.Web.Services.WebService
{
public WSE3MTOMSecureService()
{
}
//T通过服务端 X509 证书加密
// MTOM可以使用WS-Security安全协议.
[WebMethod]
public byte[] DownLoadFileWithSecurity(string fileName)
{
byte[] file = null;
String filePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\" + fileName;
file = File.ReadAllBytes(filePath);//从文件里读取字节流
return file;
}
}
// MTOM可以使用WS-Security安全协议.
[WebMethod]
public byte[] DownLoadFileWithSecurity(string fileName)
{
byte[] file = null;
String filePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\" + fileName;
file = File.ReadAllBytes(filePath);//从文件里读取字节流
return file;
}
}
3.3客户端建立控制台应用程序,添加对Web服务的引用。实例化连个代理服务类,进行文件的上传和下载。具体代码如下:
//直接进行数据传输,不需要加密
public void DownLoadFile(String fileName)
{
//实例化服务代理类
WSE3MTOMServiceWse serviceproxy = new WSE3MTOMServiceWse();
//or alternatively set the RequireMtom property on the proxy
//serviceproxy.RequireMtom = true;
//获取文件二进制字节流
byte[] loadFile = serviceproxy.DownLoadFile(fileName);
public void DownLoadFile(String fileName)
{
//实例化服务代理类
WSE3MTOMServiceWse serviceproxy = new WSE3MTOMServiceWse();
//or alternatively set the RequireMtom property on the proxy
//serviceproxy.RequireMtom = true;
//获取文件二进制字节流
byte[] loadFile = serviceproxy.DownLoadFile(fileName);
//打印数据信息
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("File has been downloaded without security sucessfully from Server: {0}", loadFile.Length);
//保存文件
String filePath = AppDomain.CurrentDomain.BaseDirectory + fileName;
Console.WriteLine("");
if (File.Exists(filePath))
File.Delete(filePath);
File.WriteAllBytes(filePath, loadFile);
}
//安全方式下载文件
public void DownLoadFileSecure(String fileName)
{
WSE3MTOMSecureServiceWse serviceproxy = new WSE3MTOMSecureServiceWse();
//Set anonymousForCertificateSecurity policy assertion when calling
//this secure service
serviceproxy.SetPolicy("ClientPolicy");
byte[] loadFile = serviceproxy.DownLoadFileWithSecurity(fileName);
//打印数据信息
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("File has been downloaded with security sucessfully from Server: {0}", loadFile.Length);
//保存文件
String filePath = AppDomain.CurrentDomain.BaseDirectory + "Secure_"+ fileName;
Console.WriteLine("");
if (File.Exists(filePath))
File.Delete(filePath);
File.WriteAllBytes(filePath, loadFile);
}
//测试非加密安全上传文件
public void UpLoadFile(String fileName)
{
String filePath = AppDomain.CurrentDomain.BaseDirectory + fileName;
//实例化服务代理
WSE3MTOMServiceWse serviceproxy = new WSE3MTOMServiceWse();
//读取文件数据
byte[] upFile = File.ReadAllBytes(filePath);
//调用方法传输数据
serviceproxy.UpLoadFile(upFile);
//输出上传文件信息
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("File has been uploaded sucessfully from Client: {0}", upFile.Length);
}
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("File has been downloaded without security sucessfully from Server: {0}", loadFile.Length);
//保存文件
String filePath = AppDomain.CurrentDomain.BaseDirectory + fileName;
Console.WriteLine("");
if (File.Exists(filePath))
File.Delete(filePath);
File.WriteAllBytes(filePath, loadFile);
}
//安全方式下载文件
public void DownLoadFileSecure(String fileName)
{
WSE3MTOMSecureServiceWse serviceproxy = new WSE3MTOMSecureServiceWse();
//Set anonymousForCertificateSecurity policy assertion when calling
//this secure service
serviceproxy.SetPolicy("ClientPolicy");
byte[] loadFile = serviceproxy.DownLoadFileWithSecurity(fileName);
//打印数据信息
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("File has been downloaded with security sucessfully from Server: {0}", loadFile.Length);
//保存文件
String filePath = AppDomain.CurrentDomain.BaseDirectory + "Secure_"+ fileName;
Console.WriteLine("");
if (File.Exists(filePath))
File.Delete(filePath);
File.WriteAllBytes(filePath, loadFile);
}
//测试非加密安全上传文件
public void UpLoadFile(String fileName)
{
String filePath = AppDomain.CurrentDomain.BaseDirectory + fileName;
//实例化服务代理
WSE3MTOMServiceWse serviceproxy = new WSE3MTOMServiceWse();
//读取文件数据
byte[] upFile = File.ReadAllBytes(filePath);
//调用方法传输数据
serviceproxy.UpLoadFile(upFile);
//输出上传文件信息
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("File has been uploaded sucessfully from Client: {0}", upFile.Length);
}
运行结果如图:
首先是上传一个文件到服务器端,然后进行下载操作。均显示成功。可以在程序的运行目录下找到下载的新文件。
4.【总结】
通过以上的介绍和学习,我们知道了一下结论:
1.MTOM机制会效率提升1/3.原因:正常文本 XML 使用 Base64 对二进制数据进行编码,这要求每三个字节对应四个字符,从而使得数据的大小增加三分之一。MTOM 能够以原始字节形式传输二进制数据,这会缩短编码/解码时间并生成较小的消息。
2.使用的场合:MTOM适合大量的数据交换,通常是大量数据情况下才有优势, 如上传文档和图片,目的在于优化对较大的二进制负载的传输。
3.缺陷:对于较小的二进制负载来说,使用 MTOM 发送 SOAP 消息会产生显著的开销。
另外提供本文的代码下载。以供大家学习参考,代码下载连接/Files/frank_xl/WSE3MTOM_FrankXuLei.rar。如有意见也欢迎交流~
Web服务驻留在IIS外,可以由系统服务、控制台程序等托管的方式比较简单,大家可以参考微软的例子,这个WCF里也有类似的寄宿宿主的概念。其实有许多相似之处。
最后在准备《WSE3.0构建Web服务安全》系列文章的过程中,我也收获不少,也希望本系列文能给您的学习带来一些帮助。包括我之前的《WCF分布式开发必备知识》系列都是学习WCF分布式重要知识点的总结。并且全部给出了详细的代码实现和注释。方便大家的学习和实际项目的应用。下面我们将正式进入WCF分布式开发的学习阶段,我会继续给出系统的介绍和详细的实现代码。希望有兴趣的朋友继续关注~谢谢
参考资料:
1.BASE64编码基于十进制的实现方法
2.MTOM编码 MSDN
本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/320503,如需转载请自行联系原作者