答案 0 :(得分:1)
你能给我们转储你收到的一个字节数据包吗?将数组传递给下面的代码,它将把它转储到输出窗口。这将有助于我们查看原始数据包。
private static string PrintByteArray(byte[] bytes){
return "byte[] bytes = {0x" + BitConverter.ToString(bytes).Replace("-", ", 0x") + "};";
}
你是否理解@Paul Sasik在解析数据的答案中所说的内容?结构位于他链接的RFC spec中。数据包的前两个字节(16位)将是版本号。我没有阅读规范,但字节可以用两种不同的方式编写,little and big endian。因此,根据规范,前两个字节应该类似于0x00 0x0a
或0x0a 0x00
。
修改强>
不要考虑比特与字节,只是后者是前者的8个集合。
规范说前16位(2字节)是与你拥有的版本号0x000a
相匹配的版本号。然后它说接下来的2个字节是整个消息的长度(以字节为单位)(实际上是八位字节,同样的事情)。您的数据为0x04b4
,其小数为1204
,这正是字节数组的长度。自1970年1月1日以来,下一个字段是一个4字节的字段,用于导出时间(以Unix / Posix时间为单位)。根据{{3}} 0x4dae8ff4
,1,303,285,748
为Wed, 20 Apr 2011 07:49:08 GMT
,其中 private static IPFIX ParseMessageHeader(byte[] bytes)
{
IPFIX ret = new IPFIX();
ret.Version = ToUInt16BigEndian(bytes, 0);
ret.Length = ToUInt16BigEndian(bytes, 2);
ret.ExportTime = (new DateTime(1970, 1, 1, 0, 0, 0)).AddSeconds(ToUInt32BigEndian(bytes, 4));
ret.SequenceNumber = ToUInt32BigEndian(bytes, 8);
ret.ObservationDomainID = ToUInt32BigEndian(bytes, 12);
ret.Sets = new List<Set>();
Int32 CurOctet = 16;
Set S;
while (true)
{
S = new Set();
S.SetId = ToUInt16BigEndian(bytes, CurOctet);
S.Length = ToUInt16BigEndian(bytes, CurOctet + 2);
S.data = bytes.Skip(CurOctet).Take(S.Length).ToArray();
ret.Sets.Add(S);
CurOctet += S.Length;
if (CurOctet >= ret.Length)
{
break;
}
}
return ret;
}
//These two functions are from here http://snipplr.com/view/15179/adapt-systembitconverter-to-handle-big-endian-network-byte-ordering-in-order-to-create-number-types-from-bytes-and-viceversa/
//BitConverter.ToUInt16 would parse the results in "little endian" order so 0x000a would actually be parsed as 0x0a00 and give you 2,560 instead of 10.
//The spec says that everything should be in "big endian" (also known as "network order"
public static UInt16 ToUInt16BigEndian(byte[] value, int startIndex)
{
return System.BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(UInt16) - startIndex);
}
public static UInt32 ToUInt32BigEndian(byte[] value, int startIndex)
{
return System.BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(UInt32) - startIndex);
}
struct IPFIX
{
public UInt16 Version;
public UInt16 Length;
public DateTime ExportTime;
public UInt32 SequenceNumber;
public UInt32 ObservationDomainID;
public List<Set> Sets;
}
struct Set
{
public UInt16 SetId;
public UInt16 Length;
public byte[] data;
public SetType SetType
{
get
{
if (SetId == 2) return SetType.TemplateSet;
if (SetId == 3) return SetType.OptionTemplate;
if (SetId > 255) return SetType.DataSet;
throw new ArgumentOutOfRangeException("SetId", "SetId not in expected range of 2, 3 or >255");
}
}
}
enum SetType { TemplateSet, OptionTemplate, DataSet };
为int
。您可以使用以下代码来解析邮件头。希望这会让你继续解析原始数据。
UInt16
要注意的一点是“endian-ness”。 Windows默认情况下将值解析为小端,但此处的所有值都需要根据规范解析为大端。普通的BitConvertor类在这里不起作用,所以上面有两个辅助函数可以根据需要调整它。此外,您会看到我使用UInt32
和Int16
而不是常规的UInt16
。这也符合规范。 {{1}}同时包含负数和正数,而{{1}}没有任何概念(尽管我们通常认为它是正数)。