WCF流模式似乎不是流式传输

时间:2012-06-29 21:22:10

标签: wcf stream

我一直在尝试构建一个WCF流的示例,仅用于测试目的,我不能确定它实际上是流式传输。

样本非常基础:

  1. 服务器返回大型二进制内容(本例中为PDF文件)
  2. 客户端将大型二进制内容写入文件。
  3. 然而,问题似乎即使我认为我已经正确配置了服务器和客户端以进行流式传输:

    1. 它实际上似乎不是流媒体转移,因为我遇到IOException消息The maximum message size quota for incoming messages (65536) has been exceeded
    2. 读取的增量为1536字节,即使我将流缓冲区设置为8192(或任何其他大小)
    3. 完整的主机代码在这里:

      using System;
      using System.IO;
      using System.ServiceModel;
      using System.ServiceModel.Description;
      
      namespace WcfStreamingHost
      {
          internal class Program
          {
              private static void Main(string[] args)
              {
                  BasicHttpBinding binding = new BasicHttpBinding();
                  binding.TransferMode = TransferMode.Streamed;
                  binding.MaxBufferSize = 65536;
                  binding.MaxReceivedMessageSize = 65536;
                  binding.ReaderQuotas.MaxBytesPerRead = 65536;
                  binding.SendTimeout = TimeSpan.FromMinutes(10);
      
                  ServiceHost host = new ServiceHost(typeof (ContentProvider), new Uri("http://charles-m4600:1234/contentprovider"));
      
                  host.Description.Behaviors.Add(new ServiceMetadataBehavior());
                  host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
                  host.AddServiceEndpoint(typeof (IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
                  host.AddServiceEndpoint(typeof (IContentProvider), binding, "streamed");
      
                  host.Open();
      
                  Console.ReadKey();
              }
          }
      
          [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
          public class ContentProvider : IContentProvider
          {
              #region IContentProvider Members
      
              [OperationBehavior(AutoDisposeParameters = true)]
              public Stream GetFile()
              {
                  Stream stream = File.OpenRead("large_file.pdf");
      
                  return stream;
              }
      
              #endregion
          }
      
          [ServiceContract]
          public interface IContentProvider
          {
              [OperationContract]
              Stream GetFile();
          }
      }
      

      完整的客户端代码在这里:

      using System;
      using System.IO;
      using System.ServiceModel;
      using WcfStreamingClient.LocalSvc;
      
      namespace WcfStreamingClient
      {
          internal class Program
          {
              private static void Main(string[] args)
              {
                  BasicHttpBinding binding = new BasicHttpBinding();
                  binding.TransferMode = TransferMode.Streamed;
                  binding.MaxBufferSize = 65536;
                  binding.MaxReceivedMessageSize = 65536;
                  binding.ReaderQuotas.MaxBytesPerRead = 65536;
                  binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
      
                  EndpointAddress address = new EndpointAddress("http://charles-m4600:1234/contentprovider/streamed");
      
                  using (ContentProviderClient client = new ContentProviderClient(binding, address))
                  {
                      using (Stream stream = client.GetFile())
                      {
                          FileInfo file = new FileInfo("output.pdf");
      
                          if (file.Exists)
                          {
                              file.Delete();
                          }
      
                          using (FileStream fileStream = file.Create())
                          {
                              const int bufferLen = 8192;
                              byte[] buffer = new byte[bufferLen];
                              int count = 0;
                              int total = 0;
                              while ((count = stream.Read(buffer, 0, bufferLen)) > 0)
                              {
                                  fileStream.Write(buffer, 0, count);
                                  total += count;
                                  Console.Out.WriteLine("Read {0} bytes", total);
                              }
                          }
                      }
                  }
              }
          }
      }
      

      我已经阅读了关于这个问题的各种其他帖子,但似乎找不到任何线索。

2 个答案:

答案 0 :(得分:3)

虽然你的帖子很久以前,我偶然发现它,并认为我会分享我的发现。

始终将最大邮件大小配额视为。无论您是否进行了流式传输。 MSDN对此非常清楚。可以另外指定最大缓冲区大小。

http://msdn.microsoft.com/en-us/library/ms731078%28v=vs.100%29.aspx

MaxReceivedMessageSize :传输引发异常之前收到的邮件(包括标头)的最大大小(以字节为单位)。

MaxBufferSize :用于流式传输数据的缓冲区的最大大小(以字节为单位)。如果未设置此传输配额,或者传输未使用流式传输,则配额值与MaxReceivedMessageSize配额值和MaxValue中较小的配额值相同。

为什么你总是有 1536字节的块,我不是很确定。但我认为这是因为以太网帧的最大尺寸(除了巨型帧):

http://en.wikipedia.org/wiki/Ethernet_frame

答案 1 :(得分:1)

MaxReceivedMessageSize是为了防止DOS攻击导致通道和MaxBufferSize控制消息缓冲区在通道上。当通道配置为仅流肥皂头获得缓冲并且正文流传输时,流块大小由服务实现控制(在您的情况下为8Kb) )和maxrecievedmessagesize文件+标题的边界大小。 maxrecieved消息大小必须等于缓冲模式下文件MaxBufferSize的大小。但是在流式传输中MaxBufferSize必须小而且MaxRecievedMessafeSize是预期的文件大小。在流模式下MaxBufferSize可以用来防止DOS攻击。