【问题标题】:Reading byte array to type/variable in a simplified way?以简化的方式读取字节数组以输入/变量?
【发布时间】:2011-06-07 13:33:05
【问题描述】:

我有一个 TCP 套接字连接,我在其中获取字节数组数据,我必须对其进行解密然后格式化,所以我正在寻找一种简单的方法来读取这个结果字节数组,我可以轻松地遍历导出它的元素我需要一个类型或变量等,为了更好地解释它,请参见下面的示例:

假设我们有字节数组(数据包是小端的,这只是假设的例子)

01 02 00 03 74 00 74 00 69 00

我想把前 2 个字节放到一个 int 中,接下来的 2 个字节放到另一个 int 中,然后作为字符串休息。

所以它看起来像这样翻译:

int first = 258;
int seconnd = 3;
string rest = "tti"

我不是 java 人,但是在 java 上,我注意到有人像这样直接读取数据包的地方很有趣:

messageSize = readH(); // for 2 bytes
key = readH(); // for 2 bytes
message = readS(); // read as string

我想知道在 c# 或任何其他资源中是否有类似的预制功能可以帮助我更好地完成这项任务?

【问题讨论】:

  • 你读的怎么样?
  • @Nik 我还没有决定,因为我不确定我必须简化阅读的选项,目前只是为了调试以确保我得到正确的数据我得到它像这样byte[] bytes = new byte[1024]; client.Receive(bytes);,因为我有几个步骤,比如初始连接回复,然后是你好回复,然后是登录回复......我将不得不格式化我想要寻找一些帮助/建议的字节。

标签: c# sockets bytearray tcpclient


【解决方案1】:

你可以像这样使用BinaryReader

using (var reader = new BinaryReader(stream))
{
    var first = reader.ReadUInt16();
    var second = reader.ReadUInt16();
    var stringBytes = reader.ReadBytes(6);
    var str = Encoding.Unicode.GetString(stringBytes);
}

但是,这只有在使用 little-endian 时才有效。

您发布的示例是大端。

我假设你在 C# 中实现了 writer 和 sender,所以你最好使用 BinaryReaderBinaryWriter,它们都使用 little-endian,所以它们会相互理解。

[编辑]

您可能要考虑的另一种方法是使用struct
例如在你的情况下:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MyStruct
{
    public ushort First;
    public ushort Second;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string MyString;
}

代码如下所示

var myStruct = new MyStruct { First = 1, Second = 2, MyString = "asd" };

var bytes = StructToBytes(myStruct);

var myStruct1 = BytesToStruct<MyStruct>(bytes);

还有两个实用方法:

public static T BytesToStruct<T>(byte[] bytes) where T : struct
{
    AssertUtilities.ArgumentNotNull(bytes, "bytes");

    var structSize = Marshal.SizeOf(typeof(T));
    var pointer = IntPtr.Zero;
    try
    {
        pointer = Marshal.AllocHGlobal(structSize);
        Marshal.Copy(bytes, 0, pointer, structSize);
        return (T)Marshal.PtrToStructure(pointer, typeof(T));
    }
    finally
    {
        if (pointer != IntPtr.Zero)
            Marshal.FreeHGlobal(pointer);
    }
}

public static byte[] StructToBytes<T>(T structObject) where T : struct
{
    var structSize = Marshal.SizeOf(typeof(T));
    var bytes = new byte[structSize];
    var pointer = IntPtr.Zero;
    try
    {
        pointer = Marshal.AllocHGlobal(structSize);
        Marshal.StructureToPtr(structObject, pointer, true);
        Marshal.Copy(pointer, bytes, 0, structSize);
        return bytes;
    }
    finally
    {
        if (pointer != IntPtr.Zero)
            Marshal.FreeHGlobal(pointer);
    }
}

【讨论】:

  • 非常好,它们实际上是小端的,但在这个例子中,我只是写了当时我想到的任何东西......不是我得到的任何字节的真实例子...... .
  • 我对 BinaryReader 方法说是,对 struct 方法说不是;后者对我的口味来说有点过于依赖实现了。例如,BinaryReader 保证始终读取数字 little-endian,即使您在 Mono 下在使用 big-endian 的架构上运行(或者如果在某些假设的未来 .Net 本身被移植到 big-endian 架构;我'不确定 ARM 上的 Windows 8 将使用什么),但在这种情况下结构方法将失败。
  • @Sven - 一切都取决于要求。在不了解要求的情况下无法确定使用什么。
  • @Marc:看起来BinaryReader 被定义为little-endian,尽管不是很清楚,例如msdn.microsoft.com/en-us/library/…
【解决方案2】:

对于简单的示例,您可以执行以下操作:

static class StreamHelpers
{
    public static int ReadH(this Stream stream)
    {
        int x = stream.ReadByte(), y = stream.ReadByte();
        if (x < 0 || y < 0) throw new EndOfStreamException();
        return (y << 8) | x;
    }
    ...

}

这使您可以访问:

int i = stream.ReadH();

等等。然而,个人我会写一个自定义的blahReader(为你的blah),带有一个内部的byte[]缓冲区和跟踪光标。这使得在大多数情况下必须更有效地阅读(即使与BufferedStream 相比)。

附带说明,您的字符串看起来是 UTF-16 并读取到 EOF;阅读 EOF 很痛苦,因为它实际上不允许您对 2 字符串进行编码。我将(而不是)添加(首先)字符串的 length,除非很有可能出现大字符点,否则我将使用 UTF-8。那么读取一个字符串就是这样一种情况:

  • 读取长度
  • 通过Encoding.*解码那么多

最后一点 - 如果您主要编写小整数,则有可能有用的整数替代编码样式(允许小值使用单字节,但仍允许完整的 int要表达的范围)。

【讨论】:

  • 最初我正在考虑做类似的事情,但我不知道我可以像 Alex 提议的那样使用 binaryreader,现在我将完全这样做,以帮助我解析/格式化所有数据。谢谢。是的,它是 UTF-16 不错的选择 :) 但我收到 UTF-16、ASCII 和 UTF8 只是为了让我的生活更加复杂,所以我需要检查初始字节码以了解消息大小和类型 ehhe。跨度>
  • 在这种情况下,您可以使用具有“bool addByte()”方法的类吗? AddByte() 将执行所有数据成员的检查和加载,并在读取完整消息后返回“true”,通过属性读取协议中的各个项目。然后该类可以处理任何转换 - 字节序、字符编码等。然后将消息数据封装在一个类实例中,并轻松传递或排队到其他线程。
猜你喜欢
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-13
  • 1970-01-01
相关资源
最近更新 更多