收到的消息packats包含多个消息,这些消息由header = 0xFD和footer = 0xFE
分隔// 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和第3条消息包含6个字节。
在while循环中,我期待TakeWhile添加不等于消息的页脚部分的字节。
注意:由于我在读取它们之后删除了字节,因此总是可以预期标题位于“0”位置。
我搜索了分裂字节数组的示例,但未证明在未知和波动大小的数组上进行拆分。
任何帮助将不胜感激。 非常感谢!
答案 0 :(得分:3)
真正棘手的部分是套接字是数据流,因此您的缓冲区实际上可能只包含部分消息。我有代码here实现一个基于单字节分隔符的“成帧器”,正确处理部分读取。它完全经过了单元测试。
请注意以下几十年经验的“框架”课程设计技巧:
答案 1 :(得分: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
所以在流程结束时,你会有一个列表&gt;
我希望它看起来不那么混乱
答案 2 :(得分: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);
}
答案 3 :(得分: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();
然而,我真的觉得Daniel的解决方案更具可读性和可维护性。 Beware the dark side.
如果你坚持使用LINQ,我建议你写一个Partition
扩展方法来清除所有这些,所以你可以拥有像receiveBuffer.Where(x => x != 0xFD).Partition(0xFE)
这样的代码。目前还没有这样的功能。