• 为wcf写个CircularStream


        wcf提供了streaming方式后,一直有个小问题,找不到合适的stream载体,如果能用上文件流什么的做返回值那是最好不过了,但是更多的情况下,需要返回一个流,但是这个流并没有类似文件之类的真实载体,而且有时候这个流还比较大(如果很小的话,也不需要用到streaming方式了),这时候似乎就有那么点麻烦了。

        首先,我不喜欢用MemoryStream,因为它真实的占用了这么多内存,遇到大数据量的情况下,wcf的streaming方式的威力将大大降低。当然,也可以借助文件,返回文件流来绕开这个问题,或者使用其他的什么现成的流。

        然而,我更倾向于使用类似Circular Buffer的逻辑来处理这个流,这样可以占用很小的内存,来输出很大体积的流,最大限度的体现wcf的streaming模式的优势。

        不过,网上查了几个Circlar Buffer的实现,总感觉不是特别满意。。。无奈之下只能自己动手打造一个:

    CircularStream
        public class CircularStream
            : Stream
        {

            #region Fields
            private const int DefaultCapacity = 0x10000;
            private readonly object SyncRoot = new object();
            private bool m_closed;
            private readonly byte[] m_buffer;
            private int m_read;
            private int m_write;
            #endregion

            #region Ctors

            public CircularStream(int capacity)
            {
                m_buffer = new byte[capacity];
            }

            public CircularStream(Action<Stream> action)
                : this(DefaultCapacity)
            {
                ThreadPool.QueueUserWorkItem(_ =>
                {
                    try
                    {
                        action(this);
                    }
                    finally
                    {
                        this.Dispose();
                    }
                });
            }

            #endregion

            #region Overrides

            public override bool CanRead
            {
                get { return true; }
            }

            public override bool CanSeek
            {
                get { return false; }
            }

            public override bool CanWrite
            {
                get { return true; }
            }

            public override void Flush() { }

            public override long Length
            {
                get { throw new NotSupportedException(); }
            }

            public override long Position
            {
                get { throw new NotSupportedException(); }
                set { throw new NotSupportedException(); }
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotSupportedException();
            }

            public override void SetLength(long value)
            {
                throw new NotSupportedException();
            }

            protected override void Dispose(bool disposing)
            {
                lock (SyncRoot)
                {
                    m_closed = true;
                    Monitor.Pulse(SyncRoot);
                }
                base.Dispose(disposing);
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                lock (SyncRoot)
                {
                    while (m_read == m_write)//empty
                        if (m_closed)
                            return 0;
                        else
                            Monitor.Wait(SyncRoot, 100true);
                    int c;
                    if (m_write > m_read)
                        c = m_write - m_read;
                    else
                        c = m_buffer.Length - m_read;
                    Monitor.Pulse(SyncRoot);
                    if (c > count)
                    {
                        Buffer.BlockCopy(m_buffer, m_read, buffer, offset, count);
                        m_read += count;
                        return count;
                    }
                    else
                    {
                        Buffer.BlockCopy(m_buffer, m_read, buffer, offset, c);
                        m_read = (m_read + c) % m_buffer.Length;
                        return c;
                    }
                }
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                lock (SyncRoot)
                {
                    if (m_closed)
                        throw new ObjectDisposedException("CircleBufferStream");
                    while (count > 0)
                    {
                        while ((m_write + 1) % m_buffer.Length == m_read)// full
                            Monitor.Wait(SyncRoot, 100true);
                        if (m_read > m_write)
                        {
                            int c = Math.Min(m_read - m_write - 1, count);
                            Buffer.BlockCopy(buffer, offset, m_buffer, m_write, c);
                            m_write += c;
                            count -= c;
                            offset += c;
                        }
                        else
                        {
                            int c = m_buffer.Length - m_write;
                            if (m_read == 0)
                                --c;
                            if (c > count)
                            {
                                Buffer.BlockCopy(buffer, offset, m_buffer, m_write, count);
                                m_write += count;
                                count = 0;
                            }
                            else
                            {
                                Buffer.BlockCopy(buffer, offset, m_buffer, m_write, c);
                                m_write = (m_write + c) % m_buffer.Length;
                                count -= c;
                                offset += c;
                            }
                        }
                        Monitor.Pulse(SyncRoot);
                    }
                }
            }

            #endregion

            #region Properties

            public int Capacity { get { return m_buffer.Length; } }

            #endregion

        }

        加上配套的契约和实现:

    契约
        [ServiceContract]
        public interface IService1
        {
            [OperationContract]
            Stream GetStream(int value);
        }
    实现
        public class Service1 : IService1
        {
            public Stream GetStream(int value)
            {
                return new CircularStream(s =>
                    new XStreamingElement("root",
                        from i in Enumerable.Range(1, value)
                        select new XElement("item",
                            new XAttribute("id", i))).Save(s));
            }
        }

        以及调用的服务和客户端:

    服务和客户端
        static class Program
        {
            static void Main(string[] args)
            {
                var host = new ServiceHost(typeof(Service1));
                host.Open();
                var binding= new BasicHttpBinding();
                binding.TransferMode=TransferMode.StreamedResponse;
                binding.MaxReceivedMessageSize = int.MaxValue;
                // 如果觉得不过瘾,可以打开循环爽一把
                
    //for (int i = 0; i < 100; i++)
                
    //{
                    new Uri("http://localhost:12123/").InvokeWcfClient<IService1>(binding, c =>
                    {
                        var stream = c.GetStream(10000);
                        string line;
                        using (var r = new StreamReader(stream))
                            while (null != (line = r.ReadLine()))
                                Console.WriteLine(line);
                    });
                //}
                host.Close();
            }

            public static void InvokeWcfClient<TChannel>(
                this Uri uri, Binding binding, Action<TChannel> action)
                where TChannel : class
            {
                TChannel client = ChannelFactory<TChannel>.CreateChannel(
                    binding, new EndpointAddress(uri));
                var co = (ICommunicationObject)client;
                try
                {
                    co.Open();
                    action(client);
                }
                finally
                {
                    if (co.State == CommunicationState.Faulted)
                        co.Abort();
                    else
                        co.Close();
                }
            }
        }

        这样就可以完美运行了

  • 相关阅读:
    如何有效的遍历django的QuerySet
    python进程池剖析(三)
    python进程池剖析(二)
    python进程池剖析(一)
    条件变量signal与unlock的顺序
    智能指针与句柄类(四)
    解析正则 /(d)(?=(d{3})+.)/g
    原生JS实现增加删除class
    RN 热更新
    Windows下搭建IOS开发环境
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/2371406.html
Copyright © 2020-2023  润新知