2010-05-18 53 views
0

接收到的數據字節陣列接收packats該消息包含由標題= 0xFD和頁腳= deliniated 0xFE的使用LINQ,需要幫助分裂來自Silverlight的插座

// sample message packet with three 
// different size messages 
List<byte> receiveBuffer = new List<byte>(); 
receiveBuffer.AddRange(new byte[] 
    { 0xFD, 1, 2, 0xFE, 
    0xFD, 1, 2, 3, 4, 5, 6, 7, 8, 0xFE, 
    0xFD, 33, 65, 25, 44, 0xFE}); 


// note: this sample code is without synchronization, 
//  statements, error handling...etc. 
while (receiveBuffer.Count > 0) 
{ 
    var bytesInRange = receiveBuffer.TakeWhile(n => n != 0xFE); 

    foreach (var n in bytesInRange) 
     Console.WriteLine(n); 

    // process message.. 
    // 1) remove bytes read from receive buffer 
    // 2) construct message object... 
    // 3) etc... 

    receiveBuffer.RemoveRange(0, bytesInRange.Count()); 

} 

正如你可以看到,(包括多個消息頭/頁腳),該消息包中的第一條消息包含4個字節,第二條消息包含10個字節,a和第三條消息包含6個字節。

在while循環中,我期待TakeWhile添加不等於消息的頁腳部分的字節。

注意:由於我在讀取它們後刪除了字節,因此始終可以將標題置於位置「0」處。

我搜索了分割字節數組的示例,但沒有證明在未知和波動大小的數組上分裂。

任何幫助將不勝感激。 非常感謝!

+0

乍一看,我看不出你發佈的代碼有什麼問題。這會產生什麼錯誤或問題? – 2010-05-18 20:02:37

回答

0

的理念是:

while not the end of receiveBuffer 
if receiverbuffer[actualposition] != 0xfe 
    insert this position in a listA 
    if receiverbuffer[actualposition] == 0xfe 
    insert the listA into another listB 
    listA become null and you go to next line 
go to next position of receivebuffer 

因此在過程結束時,你就會有一個列表>

我希望它看起來並不像很多混亂

0

不知道這只是演示代碼中引入的一個錯誤,但在從緩衝區中刪除先前消息時,您確實需要添加一個:

receiveBuffer.RemoveRange(0, bytesInRange.Count() + 1); 

代替

receiveBuffer.RemoveRange(0, bytesInRange.Count()); 

隨着這一變化,代碼打印出除了分別在三個消息中的結束標記的每個字節。

在您的代碼打印每一個身體字節用於每個郵件的以下變化:

List<byte> receiveBuffer = new List<byte>(); 
receiveBuffer.AddRange(new byte[] 
{ 
    0xFD, 1, 2, 0xFE, 
    0xFD, 1, 2, 3, 4, 5, 6, 7, 8, 0xFE, 
    0xFD, 33, 65, 25, 44, 0xFE 
}); 

while (receiveBuffer.Count > 0) 
{ 
    var bytesInRange = receiveBuffer.Skip(1).TakeWhile(n => n != 0xFE); 

    foreach (var n in bytesInRange) 
     Console.Write("{0} ", n); 

    Console.WriteLine("\n"); 
    receiveBuffer.RemoveRange(0, bytesInRange.Count() + 2); 
} 
+0

這個解決方案也工作得很好,是的,這是一個錯誤,我忘記了將1添加到接收緩衝區。 其實,我結束了使用你的例子,用Take取代TakeWhile,這似乎返回相同的結果。 我的老闆不喜歡LINQ,更喜歡將代碼放在漫長的路線上(可以這麼說)。我的觀點是,這個LINQ例子不是太難理解。無論如何,再次感謝這個偉大的例子。 我對LINQ有些不熟悉,並且從我所看到的海事組織來看,這是[佔位符]的下一個最好的東西。 – gcadmes 2010-05-20 14:45:59

3

這樣做的真正棘手的部分是,插座是數據流,所以你的緩衝器可以實際上僅包含部分信息。我的代碼here實現了一個基於單字節定界符的「成幀器」,可以正確處理部分讀取。它完全通過了單元測試。

請注意以下幾點設計技巧「成幀器」類,從幾十年的經驗:

  • 獨立的消息緩衝到一個類。緩衝代碼足夠複雜,而無需處理異步套接字。套接字事件處理程序可以負責始終保持異步讀取,處理0長度讀取和錯誤處理。然後他們應該將數據傳遞給緩衝類,緩衝類負責進行實際的構建。
  • 在編寫消息緩衝類時,如果改變對數據的思考方式,最終會得到更清晰的代碼。而不是大量的數據到達套接字並被「推送」通過緩衝類,將其視爲發出隱式「讀取請求」的緩衝類;當大塊數據進入時,做一個滿足當前「讀取請求」的循環,直到塊全部用完。
+0

優秀的源碼示例! 我確實有一個名爲SystemMessagePacket的對象框架類,它實現了一個基本的MessagePacket類。 再次感謝提示和來源。 Greg – gcadmes 2010-05-18 23:48:47

0

由於您已經有了適當的框架,是否有某些原因Daniel的解決方案不適合您?

如果你想要的東西,只是使用LINQ,這可以來完成:

int messageIndex = 0; 
var test = receiveBuffer 
    // Remove SOT bytes 
    .Where(x => x != 0xFD) 
    // Assign each byte as being part of a message, indexing on EOT 
    .Select(x => 
     { 
      if (x == 0xFE) ++messageIndex; 
      return new { Byte = x, MessageIndex = (x == 0xFE ? -1 : messageIndex) }; 
     }) 
    // Remove EOT bytes 
    .Where(x => x.MessageIndex != -1) 
    // Group by message index 
    .GroupBy(x => x.MessageIndex) 
    // Strip message index and convert the bytes in each message to a List<byte> 
    .Select(x => x.Select(y => y.Byte).ToList()) 
    // Execute the query, saving in a List<List<byte>> 
    .ToList(); 

不過,我真的覺得丹尼爾的解決方案是更具可讀性和可維護性。 Beware the dark side.

如果你堅持使用LINQ,我建議你寫一個Partition擴展方法來清除所有這些,所以你可以使用代碼如receiveBuffer.Where(x => x != 0xFD).Partition(0xFE)。目前沒有這樣的功能。