MTOM效率测试

MTOM是一种消息编码方式,它的目的是优化SOAP消息的编码,以减小体积,提高传输速度。如果你对其不清楚,可以参考另外一篇文章

http://www.cnblogs.com/chenxizhang/archive/2010/04/09/1708621.html

 

这一篇,我们主要用实例来看看到底它在性能方面有何表现

我们先做一些准备工作,编写了一个接口和服务

1. 接口

using System.ServiceModel;

namespace Services
{
    [ServiceContract]
    public interface IHelloService
    {

        [OperationContract]
        byte[] GetData();

        

    }
}

2.服务
namespace Services
{
    public class HelloWorldService:IHelloService
    {
        #region IHelloService 成员

        byte[] IHelloService.GetData()
        {
            return new byte[10000];
        }

        #endregion
    }
}

注意,我们这里的服务很简单,就是直接返回一个长度为10000的字节数组。

 

接下来编写宿主和客户端

3.宿主

using System;
using System.ServiceModel;
using Services;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(HelloWorldService)))
            {
                host.Open();
                Console.WriteLine("服务器已经准备好");
                Console.Read();
            }
        }
    }
}

宿主的配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Services.HelloWorldService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/HelloService"/>
          </baseAddresses>
        </host>
        <endpoint address="" contract="Services.IHelloService" binding="basicHttpBinding" bindingConfiguration="mtom"></endpoint>
      </service>
    </services>

    <bindings>
      <basicHttpBinding>
        <binding name="mtom" messageEncoding="Mtom"></binding>
      </basicHttpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

4. 客户端

using System;
using System.ServiceModel;
using Services;

namespace TestClient
{
    class Program
    {
        static void Main(string[] args)
        {
            IHelloService proxy =
                (new ChannelFactory<IHelloService>("local")).CreateChannel();

            byte[] buffer=proxy.GetData();
            Console.WriteLine(buffer.Length);

            Console.Read();
        }
    }
}

 

客户端的配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  
    <system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging"
      switchValue="Verbose">
        <listeners>
          <add name="xml"
          type="System.Diagnostics.XmlWriterTraceListener"
          initializeData="c:\logs\client.svclog" />
        </listeners>
      </source>
    </sources>
    <trace autoflush="true" />
  </system.diagnostics>


  
  
  <system.serviceModel>

    <diagnostics>
      <messageLogging logEntireMessage="true"
      maxMessagesToLog="300"
      logMessagesAtServiceLevel="false"
      logMalformedMessages="true"
      logMessagesAtTransportLevel="true" />
    </diagnostics>
    <client>
      <endpoint address="http://localhost:8080/HelloService" binding="basicHttpBinding" contract="Services.IHelloService" name="local" bindingConfiguration="mtom"></endpoint>
    </client>
    <bindings>
      <basicHttpBinding>
        <binding name="mtom" messageEncoding="Mtom"></binding>
      </basicHttpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

 

说明,上面的配置文件中,已经配置好了messageEncoding为Mtom. 但我们在运行程序时会分两次运行,一次是标准的编码,一次则是Mtom编码

我们通过下面的日志文件可以比较出来MTOM编码的效率优势

下图是标准编码的结果,请注意Content-length为13524

image

下图是Mtom编码的结果,请注意Content-Length为10739

image

 

最后有一点要提示的是,MTOM编码主要针对二进制结果有优势。原因在于,标准编码(Text)在对二进制数据编码的时候会采取Base64编码,使得数据平白地多出来了1/3左右。

而针对纯文本的数据,则MTOM编码的长度 总是会大于标准编码的长度。

例如我们有如下的一个方法,返回一些字符

        public string GetString()
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 1000; i++)
            {
                sb.Append("Hello");
            }
            return sb.ToString();
        }

首先看标准编码的长度,为5196

image

而MTOM编码的长度则为

image

我们再来测试一下复杂类型的情况。为了演示,我们添加了一个Employee类型在客户端和服务器之间传递。

    [DataContract]
    public class Employee {
        [DataMember]
        public string FirstName { get; set; }
        [DataMember]
        public string LastName { get; set; }

        public override string ToString()
        {
            return string.Format("{0},{1}", FirstName, LastName);
        }
    }

然后在服务中实现了一个方法

        Employee[] IHelloService.GetEmployees()
        {
            List<Employee> result = new List<Employee>();
            for (int i = 0; i < 500; i++)
            {
                result.Add(new Employee()
                {
                    FirstName = "陈",
                    LastName = "希章"
                });
            }

            return result.ToArray();
        }

我们看到,发送500个员工的数据,如果按照标准编码的话,长度大致需要43319

image

如果改成mtom呢,长度为43561,还是稍微大一些。这是因为MTOM这种编码本身会有一些额外的开销

image

 

好的,这里需要总结一下了

1. MTOM是一个编码方式

2. MTOM是针对较大的二进制数据有优化作用,相比较默认的Text编码,它传输的是接近于数据原本的格式,而Text编码方式则采用了Base64的方式进行编码。

3. 针对标准文本或者对象,MTOM并没有优化作用。

 

最后,有没有朋友想到了这样一个问题:既然是二进制的数据,能不能直接就采用二进制的方式传递呢?干嘛要去编码成文本呢?

是的,这是一个很好的问题,我们当然也可以直接采用netTcpBinding,它默认就是直接使用二进制编码

 

我们从下图是看不到长度的

image

 

但如果我们真的有兴趣,可以通过下面的代码计算得到不同的编码方式到底会有多长

        static void CompareMessageSize(int dataSize)
        {
            // Create and buffer a message with a binary payload
            byte[] binaryData = new byte[dataSize];
            Message message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "action", binaryData);
            MessageBuffer buffer = message.CreateBufferedCopy(int.MaxValue);

            // Print the size of a text encoded copy
            int size = SizeOfTextMessage(buffer.CreateMessage());
            Console.WriteLine("Text encoding with a {0} byte payload: {1}", binaryData.Length, size);

            // Print the size of an MTOM encoded copy
            size = SizeOfMtomMessage(buffer.CreateMessage());
            Console.WriteLine("MTOM encoding with a {0} byte payload: {1}", binaryData.Length, size);

            Console.WriteLine();
            message.Close();
        }

        static int SizeOfTextMessage(Message message)
        {
            // Create a text encoder
            MessageEncodingBindingElement element = new TextMessageEncodingBindingElement();
            MessageEncoderFactory factory = element.CreateMessageEncoderFactory();
            MessageEncoder encoder = factory.Encoder;

            // Write the message and return its length
            MemoryStream stream = new MemoryStream();
            encoder.WriteMessage(message, stream);
            int size = (int)stream.Length;
            
            message.Close();
            stream.Close();
            return size;
        }

        static int SizeOfMtomMessage(Message message)
        {
            // Create an MTOM encoder
            MessageEncodingBindingElement element = new MtomMessageEncodingBindingElement();
            MessageEncoderFactory factory = element.CreateMessageEncoderFactory();
            MessageEncoder encoder = factory.Encoder;

            // Write the message and return its length
            MemoryStream stream = new MemoryStream();
            encoder.WriteMessage(message, stream);
            int size = (int)stream.Length;
            
            stream.Close();
            message.Close();
            return size;
        }
posted @ 2010-04-22 18:30  陈希章  阅读(9191)  评论(3编辑  收藏  举报