首先定義一個自定義控件用來顯示每條動態。html
PushedMessage 有個PushIndex屬性,表示發送消息的index,從0開始遞增。每一個人Push的index都是從0開始,ResponseMoments 的 MessageList 是個字典,Key表示 index。sql
// // 摘要: // 拉取個人朋友們發的消息。當收到服務器回覆,將觸發ResponseMomentsReceived事件。 // // 參數: // startPullIndex: // 從哪一個index的消息開始拉取(不包含該index對應的那條)。若是startPullIndex小於0,表示拉取最新的N條。 // // latest: // latest爲true,表示拉取更新的(大於startPullIndex);爲false表示拉取以前的(小於startPullIndex)。 void Pull(long startPullIndex, bool latest); // // 摘要: // 拉取目標用戶所發的消息。當收到服務器回覆,將觸發ResponseMomentsReceived事件。 // // 參數: // ownerID: // 所要拉取的目標用戶的ID // // startPushIndex: // 從哪一個index的消息開始拉取(不包含該index對應的那條)。若是startPushIndex小於0,表示拉取最新的N條。 // // latest: // latest爲true,表示拉取更新的(大於startPullIndex);爲false表示拉取以前的(小於startPullIndex)。 void Pull(string ownerID, long startPushIndex, bool latest);
當調用這個方法時,表示獲取個人朋友們的動態,我朋友們的動態會排序,index就是用這個key表示的。數據庫
latest 參數 表示是下拉,仍是上拉。 編程
DynamicsLoader中最主要的是Load方法。服務器
public void Load(Dictionary<long, PushedMessage> currentMessageList, FlowLayoutPanel flowLayoutPanel, IMomentsClient client) { this.preLastIndex = this.lastIndex; foreach (var item in currentMessageList) { if (this.firstIndex < 0) { this.firstIndex = item.Key - currentMessageList.Count + 1; } if (item.Key < this.firstIndex) { this.firstIndex = item.Key; } if (item.Key > this.lastIndex) { this.lastIndex = item.Key; } if (!this.messageList.ContainsKey(item.Key)) { this.messageList.Add(item.Key, item.Value); } } this.freeIndex = this.lastIndex - 20; if ((this.lastIndex - this.preLastIndex) > 39) { this.firstIndex = this.lastIndex - currentMessageList.Count + 1; this.preLastIndex = this.firstIndex; this.freeIndex = this.preLastIndex; this.messageList.Clear(); this.messageList = currentMessageList; } this.listIndex = new List<long>((IEnumerable<long>)this.messageList.Keys); this.listIndex.Sort(); flowLayoutPanel.Controls.Clear(); foreach (var item in this.listIndex) { DynamicsControl crl = new DynamicsControl(); crl.Initialize(this.messageList[item].OwnerID, Encoding.UTF8.GetString(this.messageList[item].Content), this.messageList[item].PushTime); flowLayoutPanel.Controls.Add(crl); flowLayoutPanel.Controls.SetChildIndex(crl, 0); } this.listIndex.Clear(); this.listIndex = null; if (this.isUp) { if (flowLayoutPanel.Controls.Count != 0) { flowLayoutPanel.ScrollControlIntoView(flowLayoutPanel.Controls[0]); } } else { if (flowLayoutPanel.Controls.Count != 0) { flowLayoutPanel.ScrollControlIntoView(flowLayoutPanel.Controls[flowLayoutPanel.Controls.Count - 1]); } } if (currentMessageList.Count == 0) { return; } if ((this.lastIndex - this.preLastIndex) < 20) { return; } do { client.Pull(this.freeIndex, false); this.freeIndex -= 20; } while (this.freeIndex > this.preLastIndex); }
正如前面所言,每一條動態都有一個index,那麼我每次獲取動態的時候,就須要保留一個最小的索引,用於下拉的時候使用;保留一個最大的索引,用於上拉的時候使用。當最新的動態比本地的動態多出20條以上時,則分爲兩種狀況:1.兩次能夠加載完的就加載兩次 ,2兩次沒法加載完的,就只加載最新的20條,並將本地舊動態所有刪除。 網絡
NPush默認使用緊湊的序列化器,其遵循的策略以下:
字符串一概使用UTF-8編碼。若是是基礎數據類型,則直接記錄其字節。
若是是bool,則用一個字節表示,0表示false,1表示true。
若是是string,先記錄其長度(int,-1表示爲null,0表示string.Empty),再記錄UTF8編碼的字節。
若是是byte[],先記錄其長度(int,-1表示爲null),再記錄其內容。
若是是Image ,先記錄其長度(int,-1表示爲null),再記錄是否爲Gif(一個byte),再記錄序列化內容。
若是是Color ,長度固定爲3個字節,一次記錄R/G/B的值。
若是是List<>,先記錄元素數(int,-1表示爲null),再依次記錄每一個元素的內容。
若是是Dictionary<,>,先記錄元素對的個數(int,-1表示爲null),再依次記錄每一個元素的Key,Value。
若是是自定義的class和struct,則先記錄其序列化的長度(int,-1表示爲null),再記錄其序列化後的內容 分佈式
消息頭固定長度爲8。ide
以登錄請求消息爲例:LoginContract,C->S,MessageType爲0 post
DeviceType取值: 0 - DotNet ,1 - Android ,2 - iOS 性能
在分佈式通訊系統中,網絡傳遞的是二進制流,而內存中是咱們基於對象模型構建的各類各樣的對象,當咱們須要將一個對象經過網絡傳遞給另外一個節點時,首先須要將其序列化爲字節流,而後經過網絡發送給目標節點,目標節點接收後,再反序列化爲對象實例。
爲了將業務對象轉換爲二進制流,你們一般有兩種方案能夠選擇:使用.NET自帶的二進制序列化器,或,先將業務對象轉換爲字符串(好比xml),再將結果用相似UTF8進行編碼獲得字節流。 然而這兩種方案都有缺陷。
缺點:強侵入性,序列化結果臃腫,其size巨大,效率低下,加密困難。
缺點:須要本身打造協議對象與字符串之間的相互轉換、序列化以後的結果的Size取決於咱們協議對象與字符串之間相互轉換時所採用的規則,一樣也取決於咱們的耐心程度 、同.NET自帶的二進制序列化器,對象屬性值的讀取/設置、對象的建立等一般也是基於反射的,因此,效率一樣存在問題。
基於上述,我選擇採用本身的序列化方式,性能較.NET自帶的二進制序列化器提升了7~8倍。
(說明:壓縮包中有SQL腳本,我使用的是Mysql數據庫。客戶端登錄帳號爲test01~test99,以及默認的testQQ。相應的好友關係能夠查看服務端的TestFriendProvider類。 )
——————————————————————————————————————