前陣子的工作涉及一些網絡編程,使用了面向流的方式做傳輸數據。在代碼過程中,遇到一個新需求就是要統計流量。其實最簡單的辦法就時在讀寫流的地方增加代碼,把功能增加上去就可以。但是我覺得那樣對我原理的代碼框架影響較大,基于盡量不影響原來的代碼的考慮,我想到了decorator設計模式。
先把代碼貼出來,在做解釋吧:
| 以下為引用的內容: public class eventstream : stream { public event eventhandler<fstreamdataeventargs> onbeforeread; public event eventhandler<fstreamdataeventargs> onbeforewrite; private stream stream; [ ==== stream members ==== ]#region [ ==== stream members ==== ] public override bool canseek public override bool canwrite public override void flush() public override long length public override long position public override int read(byte[] buffer, int offset, int count) public override long seek(long offset, seekorigin origin) public override void setlength(long value) public override void write(byte[] buffer, int offset, int count) public override iasyncresult beginread(byte[] buffer, int offset, int count, public override int endread(iasyncresult asyncresult) public override iasyncresult beginwrite(byte[] buffer, int offset, int count, asynccallback callback, object state) public override void endwrite(iasyncresult asyncresult) #endregion private class internalcallback public internalcallback(eventhandler<fstreamdataeventargs> internalhandler, asynccallback callback) internal void callback(iasyncresult asyncresult) private class internalasyncstate public object state public fstreamdataeventargs streamdataeventargs public internalasyncstate(fstreamdataeventargs streamdataeventargs, object state) private class eventstreamasyncresult : iasyncresult public eventstreamasyncresult(iasyncresult ar) public object asyncstate internal iasyncresult internalasyncresult public system.threading.waithandle asyncwaithandle public bool completedsynchronously public bool iscompleted #endregion public class fstreamdataeventargs : eventargs public fstreamdataeventargs(byte[] buffer, int offset, int count) this.buffer = buffer; /**//// <summary> /**//// <summary> /**//// <summary> |
剛開始以為很簡單,事實上寫下來還挺多行代碼的,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) |
在不更改這個“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中的類都給包裝起來,并在完成原來的功能之余另外加了自己的功能。
文筆一般,希望能對你有幫助。
注冊會員,創建你的web開發資料庫,新聞熱點
疑難解答