ESFramework介绍之(16)―― Tcp数据自动发送器ITcpAutoSender
??? 我們已經積累了這樣的經驗:如果有一個大塊的數據需要通過Tcp發送,我們會采用異步的方式以避免當前工作線程阻塞。那么,如果我們有多個線程需要同時發送大塊的數據了?每個線程都在NetworkStream或Socket上提交異步發送數據的請求會導致數據發送的混亂(多個線程同時在一個Socket上進行寫操作),所以,我引入了前面介紹的線程安全的網絡流。在引入這個類后,似乎日子已經很好過了,但是新的功能要求使得我需要尋找另外的解決方案。
??? 考慮一下這個情景:我們的即時通信軟件AgileIM在和好友進行視頻聊天的同時,還要傳遞文字信息、音頻數據、重要文件數據、控制命令等。而需要被傳送的這些信息是有優先級順序的,比如,控制命令的優先級最高,文件數據的優先級較低,而視頻數據/音頻數據在網絡特別繁忙的時候是可以丟棄的。為了管理這些優先級,僅僅依靠ISafeNetworkStream已經不能滿足我們的要求,我們需要另外一個組件來為我們解決這個問題,ESFramework提供的ITcpAutoSender組件正是為此目的的。
??? 我們知道,在多線程的環境中對像Socket這樣臨界資源的訪問必須保證線程安全,從另外一個角度來看,可以這么說,對某個臨界資源的訪問必須是同步的或者說必須是“仿單線程”的。 ITcpAutoSender就利用了這一“仿單線程”特性使的問題簡單化。我們來看看這個組件究竟是如何工作的?
??? 我們的應用程序中的各個線程當有數據需要發送時,就將數據提交ITcpAutoSender,提交時必須指定該數據的優先級。ITcpAutoSender組件會根據指定的優先級將該數據放入到對應的隊列中,請注意,將要發送的數據提交給ITcpAutoSender必須是線程安全的,這點已經由ITcpAutoSender組件保證,使用者不用關心。
????ITcpAutoSender內部有一個循環線程,每次從高優先級的隊列中選取一個數據包進行發送,當高優先級隊列為空時,再去發送次高優先級隊列中的數據。每當一個數據包發送完畢,就再從高優先級的隊列開始檢查,如此反復。
??? 從上面的描述已經可以看出,ITcpAutoSender組件僅僅是在一個線程中發送數據,所以ITcpAutoSender組件不需要再借助ISafeNetworkStream組件,而是直接使用NetworkStream就可以了。那么是不是ESFramework就不需要提供ISafeNetworkStream組件了?不是。在ESFramework框架中,ISafeNetworkStream組件主要用于服務端,因為通常情況下,服務端主動發送數據給客戶端的幾率比較小,而且服務端要管理成千上萬的連接,所以使用ISafeNetworkStream組件是非常合適的。而ITcpAutoSender組件最常用于客戶端,為客戶端應用提供發送的數據的優先級機制。如果對你的應用中的客戶端來說,所有的數據的優先級是一樣的,那么就沒有必要使用ITcpAutoSender組件了,直接使用ISafeNetworkStream就可以了。
?
??? 在ESFramework框架中,將數據的優先級分為4等,如下枚舉定義所示:
2?????{
3?????????High?,//緊急命令
4?????????Common?,//如普通消息,如聊天消息
5?????????Low?,//如文件傳輸
6?????????CanBeDiscarded?//如視頻數據、音頻數據
7?????}
??? 對于每個優先級,ITcpAutoSender組件的實現中都有一個對應的隊列,每個隊列都設置了初始大小。對于前三個優先級隊列,當它們Full的時候,應用中的線程再提交數據就必須阻塞等待。而對于最低優先級CanBeDiscarded的隊列,如果Full的時候有數據提交過來,則會刪除隊列頭部的待發送數據。下面給出ITcpAutoSender組件的接口定義:
???
?2?????{
?3?????????void?Initialize()?;
?4?????????void?SendData(byte[]?data,?DataPriority?dataPriority);??????
?5?????????void?ClearQueue(DataPriority?queueType)?;
?6?????????event?CbDataDiscarded?DataDiscarded;
?7?????????event?CbDataLacked????DataLacked;
?8?????????event?CbSimple????????ConnectionInterrupted?;
?9?
10?????????int?QueueSizeOfDiscarded?{?get;?set;}
11?????????int?QueueSizeOfNonDiscarded?{?get;?set;}
12?????????NetworkStream?NetworkStream?{?set;}
13?????}????
14?
15?????public?delegate?void?CbDataDiscarded(byte[]?data)?;
16?????public?delegate?void?CbDataLacked()?;
??? 注意,這個接口中發布DataDiscarded事件和DataLacked事件,當網絡繁忙有數據被拋棄時,DataDiscarded事件被觸發;當所有的待發送隊列都為空時,DataLacked事件被觸發。我們的應用可以預定這兩個事件來作些適當的調度。比如在AgileIM中,當DataDiscarded事件發生時,就適當減少視頻捕獲的幀率;當DataLacked事件發生時,就適當增大視頻捕獲的幀率,以達到更好的視頻會話效果。
??? 最后,說一下,很多朋友想得到ESFramework的源代碼,這要等到ESFramework開源以后,相信這不是很久遠的事情了。這里,我把ESFramework.dll提供給大家下載適用,當然你也可以用反射工具看看其中的構造。如果你想在你的項目中使用ESFramework,我將非常樂意回答你遇到的各種問題,你可以通過AgileSoft@163.com聯系我。
??? 謝謝關注!
上一篇文章:ESFramework介紹之(15)-- IRAS
轉到??:ESFramework 可復用的通信框架(序)?
?
總結
以上是生活随笔為你收集整理的ESFramework介绍之(16)―― Tcp数据自动发送器ITcpAutoSender的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2005年中国之“至理名言”
- 下一篇: ESFramework介绍之(21)--