繁体中文
设为首页
加入收藏
当前位置:网络编程首页 >> .Net编程 >> 封装stream,在读写stream时提供事件通知

封装stream,在读写stream时提供事件通知

2007-12-15 17:10:35  作者:  来源:  浏览次数:1009  文字大小:【】【】【

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

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

 


 ublic cla  EventStream : Stream
  {
  public event EventHandler<FStreamDataEventArg gt; O eforeRead;
  public event EventHandler<FStreamDataEventArg gt; O eforeWrite;

  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 Ca eek
  {
  get { return stream.Ca eek; }
  }

  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.Positio 
  }
  set
  {
  stream.Position = value;
  }
  }

  public override int Read(byte[] buffer, int offset, int count)
  {
  int readSize = stream.Read(buffer, offset, count);
  if (O eforeRead != null)
  O eforeRead(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 (O eforeWrite != null)
  O eforeWrite(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(O eforeRead, 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(O eforeWrite, callback).Callback);
  return new EventStreamAsyncResult(
  stream.BeginWrite(buffer, offset, count, myCallback, myState));
  }

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

  #endregion

  private cla  InternalCallback
  {
  private AsyncCallback callback;
  private EventHandler<FStreamDataEventArg gt; internalHandler;

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

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

  private cla  InternalAsyncState
  {
  object state;
  FStreamDataEventArgs streamDataEventArg 

  public object State
  {
  get { return state; }
  }

  public FStreamDataEventArgs StreamDataEventArgs
  {
  get { return streamDataEventArg  }
  }

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

  private cla  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 cla  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("FStreamDataEventArg quot;);
  if(offset + count> uffer.Length) throw new ArgumentOutOfRangeException("FStreamDataEventArg quot;);

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

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

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

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

刚开始以为很简单,事实上写下来还挺多行代码的,Decorator模式嘛,当然先继承stream,把stream本来该做的事情先完成了。这个很简单类里面包含一个内部的stream,stream该有的接口都由它来完成了。接下来就是增加两个事件,分别是O eforeRead、O eforeWrite。名字里面都有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 GetRe o eStream()
{
  EventStream es = new EventStream(tcpClient.NetStream);
  es.O eforeRead += new EventHandler<FStreamDataEventArg gt;(EventStream_O eforeRead);
  es.O eforeWrite += new EventHandler<FStreamDataEventArg gt;(EventStream_O eforeWrite);
  return e 
}

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

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

责任编辑:


相关文章
 

最新文章

更多

· ASP.NET立即上手教程(12)
· ASP.NET立即上手教程(13)
· ASP.NET立即上手教程(14)
· .NET环境下几种不同的邮...
· Repeater控件分页例子
· 从文本文件读取行信息
· Asp.Net 2.0数据库基本操...
· url传递中文的解决方案
· 如何实现无刷新的Dropdo...
· 将非模态对话框显示为模...

推荐文章

更多

· ASP.NET立即上手教程(12)
· ASP.NET立即上手教程(13)
· ASP.NET立即上手教程(14)
· .NET环境下几种不同的邮...
· Repeater控件分页例子
· 从文本文件读取行信息
· Asp.Net 2.0数据库基本操...
· url传递中文的解决方案
· 如何实现无刷新的Dropdo...
· 将非模态对话框显示为模...

热点文章

更多