当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > 封装stream,在读写stream时提供事件通知

ASP.NET
asp.net GridView控件中模板列CheckBox全选、反选、取消
asp.net GridView 删除时弹出确认对话框(包括内容提示)
asp.net DropDownList 三级联动下拉菜单实现代码
asp DataTable添加列和行的三种方法
Asp.net 页面调用javascript变量的值
asp.net 长文章通过设定的行数分页
asp.net 定时间点执行任务的简易解决办法
asp.net 页面延时五秒,跳转到另外的页面
asp.net 动态输出透明gif图片
asp.net DataList与Repeater用法区别
asp.net Javascript获取CheckBoxList的value
asp.net程序在调式和发布之间图片路径问题的解决方法
asp.net下生成英文字符数字验证码的代码
asp.net 页面版文本框智能提示JSCode (升级版)
ASP.NET URL伪静态重写实现方法
ASP.NET 2.0 中Forms安全认证
asp.net 动态添加多个用户控件
asp.net Repeater显示父子表数据,无闪烁
asp.net 无法获取的内部内容,因为该内容不是文本 的解决方法
asp.net GridView排序简单实现

ASP.NET 中的 封装stream,在读写stream时提供事件通知


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-23   浏览: 49 ::
收藏到网摘: n/a

前阵子的工作涉及一些网络编程,使用了面向流的方式做传输数据。在代码过程中,遇到一个新需求就是要统计流量。其实最简单的办法就时在读写流的地方增加代码,把功能增加上去就可以。但是我觉得那样对我原理的代码框架影响较大,基于尽量不影响原来的代码的考虑,我想到了Decorator设计模式。

先把代码贴出来,在做解释吧:

   

以下为引用的内容:
 public class EventStream : Stream
    {
        public event EventHandler<FStreamDataEventArgs> OnBeforeRead;
        public event EventHandler<FStreamDataEventArgs> OnBeforeWrite;

        private Stream stream;
        public EventStream(Stream stream)
        {
            if (stream == null) throw new ArgumentNullException("EventStream");
            this.stream = stream;
        }

        [ ==== Stream members ==== ]#region [ ==== Stream members ==== ]
        public override bool CanRead
        {
            get { return stream.CanRead; }
        }

        public override bool CanSeek
        {
            get { return stream.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return stream.CanWrite; }
        }

        public override void Flush()
        {
            stream.Flush();
        }

        public override long Length
        {
            get { return stream.Length; }
        }

        public override long Position
        {
            get
            {
                return stream.Position;
            }
            set
            {
                stream.Position = value;
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            int readSize = stream.Read(buffer, offset, count);
            if (OnBeforeRead != null)
                OnBeforeRead(this, new FStreamDataEventArgs(buffer, offset, readSize));
            return readSize;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return stream.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            stream.SetLength(value);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            if (OnBeforeWrite != null)
                OnBeforeWrite(this, new FStreamDataEventArgs(buffer, offset, count));
            stream.Write(buffer, offset, count);
        }

        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
            AsyncCallback callback, object state)
        {
            InternalAsyncState myState = new InternalAsyncState(
                              new FStreamDataEventArgs(buffer, offset, count), state);
            AsyncCallback myCallback = new AsyncCallback(
                              new InternalCallback(OnBeforeRead, callback).Callback);
            return new EventStreamAsyncResult(
                                 stream.BeginRead(buffer, offset, count, myCallback, myState));
        }

        public override int EndRead(IAsyncResult asyncResult)
        {
            EventStreamAsyncResult esar = asyncResult as EventStreamAsyncResult;
            if (esar != null)
                return stream.EndRead(esar.InternalAsyncResult);
            else
                return stream.EndRead(asyncResult);
        }

        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            InternalAsyncState myState = new InternalAsyncState(
                              new FStreamDataEventArgs(buffer, offset, count), state);
            AsyncCallback myCallback = new AsyncCallback(
                              new InternalCallback(OnBeforeWrite, callback).Callback);
            return new EventStreamAsyncResult(
                              stream.BeginWrite(buffer, offset, count, myCallback, myState));
        }

        public override void EndWrite(IAsyncResult asyncResult)
        {
            stream.EndWrite(asyncResult);
        }

        #endregion

        private class InternalCallback
        {
            private AsyncCallback callback;
            private EventHandler<FStreamDataEventArgs> internalHandler;

            public InternalCallback(EventHandler<FStreamDataEventArgs> internalHandler, AsyncCallback callback)
            {
                this.internalHandler = internalHandler;
                this.callback = callback;
            }

            internal void Callback(IAsyncResult asyncResult)
            {
                InternalAsyncState myState = asyncResult.AsyncState as InternalAsyncState;
                if (internalHandler != null && myState != null)
                    internalHandler(this, myState.StreamDataEventArgs);
                callback(new EventStreamAsyncResult(asyncResult));
            }
        }

        private class InternalAsyncState
        {
            object state;
            FStreamDataEventArgs streamDataEventArgs;

            public object State
            {
                get { return state; }
            }

            public FStreamDataEventArgs StreamDataEventArgs
            {
                get { return streamDataEventArgs; }
            }

            public InternalAsyncState(FStreamDataEventArgs streamDataEventArgs, object state)
            {
                this.streamDataEventArgs = streamDataEventArgs;
                this.state = state;
            }
        }

        private class EventStreamAsyncResult : IAsyncResult
        {
            IAsyncResult ar;

            public EventStreamAsyncResult(IAsyncResult ar)
            {
                if (ar == null) throw new ArgumentNullException("EventStreamAsyncResult");
                this.ar = ar;
            }
            IAsyncResult Members#region IAsyncResult Members

            public object AsyncState
            {
                get
                {
                    InternalAsyncState myState = ar.AsyncState as InternalAsyncState;
                    if (myState != null)
                        return myState.State;
                    else
                        return ar.AsyncState;
                }
            }

            internal IAsyncResult InternalAsyncResult
            {
                get { return ar; }
            }

            public System.Threading.WaitHandle AsyncWaitHandle
            {
                get { return ar.AsyncWaitHandle; }
            }

            public bool CompletedSynchronously
            {
                get { return ar.CompletedSynchronously; }
            }

            public bool IsCompleted
            {
                get { return ar.IsCompleted; }
            }

            #endregion
        }
    }

    public class FStreamDataEventArgs : EventArgs
    {
        private byte[] buffer;
        private int offset;
        private int count;

        public FStreamDataEventArgs(byte[] buffer, int offset, int count)
        {
            if(buffer == null) throw new ArgumentNullException("FStreamDataEventArgs");
            if(offset + count>buffer.Length) throw new ArgumentOutOfRangeException("FStreamDataEventArgs");

            this.buffer = buffer;
            this.offset = offset;
            this.count = count;
        }

        /**//// <summary>
        /// 数据缓存
        /// </summary>
        public byte[] Buffer
        {
          get { return buffer; }
        }

        /**//// <summary>
        /// 数据开始位置
        /// </summary>
        public int Offset
        {
          get { return offset; }
        }

        /**//// <summary>
        /// 数据长度
        /// </summary>
        public int Count
        {
          get { return count; }
        }
    }

刚开始以为很简单,事实上写下来还挺多行代码的,Decorator模式嘛,当然先继承stream,把stream本来该做的事情先完成了。这个很简单类里面包含一个内部的stream,stream该有的接口都由它来完成了。接下来就是增加两个事件,分别是OnBeforeRead、OnBeforeWrite。名字里面都有Before,其实我考虑到数据流都会通过这两个事件开放出来,你想做加密什么的都可以,当然也包括我想要的统计数据流量。

接下来就是在读写流的时候触发这两个事件就可以了。看看同步的Read、Write方法,简单的调用就可以了。
关键的地方就在于异步的读写。

我们先看看一般Stream的异步调用代码是怎么样的:

以下为引用的内容:

stream.BeginRead(buffer, 0, byte2read, new AsyncCallback(EndReadCallback), state);

private void EndReadCallback(IAsyncResult asyncResult)
{
    object state = asyncResult.AsyncState;
    nReadSize = stream.EndRead(asyncResult);
            //
}

在不更改这个“client”代码的情况下,要怎么样在stream那边知道这里的确实读了多少数据呢?

显然在调用BeginRead的时候是不知道,那就只能对这个AsyncCallback做手脚了。可以预想到framework内部会在完成了Read的操作之后会调用AsyncCallback委托来通知结果。于是我就传一个我定义好的AsyncCallback委托给BeginRead。当然还要把“client”提供的AsyncCallback给包装起来,在做完我的事情(事件通知)之后,还是要把“client”要我办的事情给也给办了(调用"client"的AsyncCallback委托来通知结果)。

这就在实现了“在客户代码与framework之间插一脚”。

再来看看我是怎么做到事件通知的。首先要把我要的数据给传过去,于是有了InternalAsyncState,这里面要有我触发事件需要的事件参数,还应该要包括用户可能传入的state。具体大家看看InternalAsyncState的实现。

最后多考虑了一点就是,假如“client”代码不是像我写的那样,而是不断的通过检查Stream.BeginRead 方法返回的IAsyncResult的IsCompleted属性来确定是否Read完成的话,那我的代码就有问题了,我返回的IAsyncResult根本就不是原理的IAsyncResult了。EventStreamAsyncResult类就是为这个而写的。
下面是使用的代码:

以下为引用的内容:
public void GetResponseStream()
{
        EventStream es = new EventStream(tcpClient.NetStream);
        es.OnBeforeRead += new EventHandler<FStreamDataEventArgs>(EventStream_OnBeforeRead);
        es.OnBeforeWrite += new EventHandler<FStreamDataEventArgs>(EventStream_OnBeforeWrite);
        return es;
}

回头看看代码,其实都在用Decorator模式的思想,把原来的framework中的类都给包装起来,并在完成原来的功能之余另外加了自己的功能。

文笔一般,希望能对你有帮助。