Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 以简化的方式将字节数组读取为类型/变量?_C#_Sockets_Bytearray_Tcpclient - Fatal编程技术网

C# 以简化的方式将字节数组读取为类型/变量?

C# 以简化的方式将字节数组读取为类型/变量?,c#,sockets,bytearray,tcpclient,C#,Sockets,Bytearray,Tcpclient,我有一个TCP套接字连接,在那里我得到数据的字节数组,我必须解密然后格式化,因此我正在寻找一种简单的方法来读取这个结果字节数组,我可以轻松地遍历元素,将其导出为类型或变量等,以便更好地解释它,请参见以下示例: 假设我们有字节数组(数据包是小端的,这只是一个算术示例): 01 02 00 03 74 00 74 00 69 00 我想把前两个字节放在一个int中,下两个字节放在另一个int中,剩下的作为字符串 所以它看起来是这样翻译的: int first = 258; int seconnd

我有一个TCP套接字连接,在那里我得到数据的字节数组,我必须解密然后格式化,因此我正在寻找一种简单的方法来读取这个结果字节数组,我可以轻松地遍历元素,将其导出为类型或变量等,以便更好地解释它,请参见以下示例:

假设我们有字节数组(数据包是小端的,这只是一个算术示例)

01 02 00 03 74 00 74 00 69 00
我想把前两个字节放在一个int中,下两个字节放在另一个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
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);
}

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

您可以像这样使用
BinaryReader

messageSize = readH(); // for 2 bytes
key = readH(); // for 2 bytes
message = readS(); // read as string
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时,这才有效

您发布的示例是big endian

我假设您在C#中实现了writer和sender,因此您可以使用
BinaryReader
BinaryWriter
,它们都使用little-endian,以便彼此理解

[编辑]

您可能需要考虑的另一种方法是使用<代码>结构> <代码>。 例如,在您的案例中:

[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);
var myStruct=newmystruct{First=1,Second=2,MyString=“asd”};
var bytes=structBytes(myStruct);
var myStruct1=BytesToStruct(字节);
和两种实用方法:

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);
    }
}
公共静态T BytesToStruct(字节[]字节),其中T:struct
{
AssertUtilities.ArgumentNotNull(字节,“字节”);
var structSize=Marshal.SizeOf(typeof(T));
变量指针=IntPtr.Zero;
尝试
{
指针=Marshal.AllocHGlobal(structSize);
副本(字节、0、指针、结构大小);
return(T)Marshal.PtrToStructure(指针,typeof(T));
}
最后
{
if(指针!=IntPtr.Zero)
自由全局元帅(指针);
}
}
公共静态字节[]structBytes(T structObject),其中T:struct
{
var structSize=Marshal.SizeOf(typeof(T));
var bytes=新字节[structSize];
变量指针=IntPtr.Zero;
尝试
{
指针=Marshal.AllocHGlobal(structSize);
StructureToPtr(structObject,指针,true);
副本(指针、字节、0、结构大小);
返回字节;
}
最后
{
if(指针!=IntPtr.Zero)
自由全局元帅(指针);
}
}

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

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;
    }
    ...

}
然而,就我个人而言,我将编写一个定制的
blahReader
(用于您的
blah
),带有一个内部
byte[]
缓冲区和跟踪光标。在大多数情况下(甚至与
BufferedStream
)相比),这允许更高效的读取

作为旁注,您的字符串看起来是UTF-16并读取到EOF;读取EOF是一件痛苦的事情,因为它实际上不允许您对2个字符串进行编码。我将(代替)添加(首先)字符串的长度,并且我将使用UTF-8,除非很有可能出现大字符点。然后读取字符串是以下情况之一:

  • 读长度
  • 通过
    编码来解码这些内容。*

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

你是如何读取流的?@Nik我还没有决定,因为我不确定简化读取的选项,目前只是为了调试以确保获得正确的数据,我是这样获得的
byte[]bytes=new byte[1024];client.Receive(字节)BinaryReader
被定义为little endian,虽然不是很清楚,例如,最初我想做类似的事情,但我不知道我可以像Alex建议的那样使用BinaryReader,现在,为了帮助我解析/格式化所有数据,我将完全支持这一点。谢谢是的,这是UTF-16很好的捕获:)但我确实收到了UTF-16、ASCII和UTF8,只是为了让我的生活更复杂一些,所以我需要检查初始字节码以了解消息的大小和类型EHE。在这种情况下,你能使用一个带有“bool addByte()”方法的类吗?AddByte()将执行所有数据成员的检查和加载,并在读取完整消息后返回“true”,通过属性读取协议中的各个项。然后,该类可以处理任何转换-endianness、char编码等。然后,消息数据被封装在一个类实例中,并可以轻松地传递给其他线程或排队给其他线程。