4

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

该示例非常基本:

  1. 服务器返回大型二进制内容(本例中为 PDF 文件)
  2. 客户端将大型二进制内容写入文件。

但是,问题似乎是即使我相信我已经正确配置了服务器和客户端以进行流传输:

  1. 它似乎实际上不是流传输,因为我遇到IOException了消息The maximum message size quota for incoming messages (65536) has been exceeded
  2. 读取以 1536 字节为增量,即使我将流缓冲区设置为 8192(或任何其他大小)

完整的主机代码在这里:

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);
                        }
                    }
                }
            }
        }
    }
}

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

4

2 回答 2

4

尽管您的帖子是很久以前的,但我偶然发现了它,并认为我会分享我的发现。

始终考虑最大邮件大小配额。无论您是否有流式传输。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

于 2014-02-05T16:38:36.933 回答
2

MaxReceivedMessageSize 用于防止对传入通道的 DOS 攻击,MaxBufferSize 控制通道上的消息缓冲区大小。当通道配置为流式传输时,仅缓冲soap标头并流式传输主体,流块大小由服务实现控制(在您的情况下为 8Kb),并且maxrecievedmessagesize 限制文件+标题的大小。maxrecieved 消息大小必须等于缓冲模式下文件 MaxBufferSize 的大小。但是在流式传输中 MaxBufferSize 必须很小,并且 MaxRecievedMessafeSize 是预期的文件大小。在流式传输模式下,可以使用 MaxBufferSize 来防止 DOS 攻击。

于 2012-06-30T06:54:52.917 回答