2010-05-18 25 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)。目前没有这样的功能。