Как преобразовать структуру в массив байтов в C#?

Как я преобразовываю структуру в массив байтов в C#?

Я определил структуру как это:

public struct CIFSPacket
{
    public uint protocolIdentifier; //The value must be "0xFF+'SMB'".
    public byte command;

    public byte errorClass;
    public byte reserved;
    public ushort error;

    public byte flags;

    //Here there are 14 bytes of data which is used differently among different dialects.
    //I do want the flags2. However, so I'll try parsing them.
    public ushort flags2;

    public ushort treeId;
    public ushort processId;
    public ushort userId;
    public ushort multiplexId;

    //Trans request
    public byte wordCount;//Count of parameter words defining the data portion of the packet.
    //From here it might be undefined...

    public int parametersStartIndex;

    public ushort byteCount; //Buffer length
    public int bufferStartIndex;

    public string Buffer;
}

В моем основном методе я создаю экземпляр его и присваиваю значения ему:

CIFSPacket packet = new CIFSPacket();
packet.protocolIdentifier = 0xff;
packet.command = (byte)CommandTypes.SMB_COM_NEGOTIATE;
packet.errorClass = 0xff;
packet.error = 0;
packet.flags = 0x00;
packet.flags2 = 0x0001;
packet.multiplexId = 22;
packet.wordCount = 0;
packet.byteCount = 119;

packet.Buffer = "NT LM 0.12";

Теперь я хочу отправить этот Пакет сокетом. Для этого я должен преобразовать структуру в массив байтов. Как я могу сделать это?

Мой полный код следующие.

static void Main(string[] args)
{

  Socket MyPing = new Socket(AddressFamily.InterNetwork,
  SocketType.Stream , ProtocolType.Unspecified ) ;


  MyPing.Connect("172.24.18.240", 139);

    //Fake an IP Address so I can send with SendTo
    IPAddress IP = new IPAddress(new byte[] { 172,24,18,240 });
    IPEndPoint IPEP = new IPEndPoint(IP, 139);

    //Local IP for Receiving
    IPEndPoint Local = new IPEndPoint(IPAddress.Any, 0);
    EndPoint EP = (EndPoint)Local;

    CIFSPacket packet = new CIFSPacket();
    packet.protocolIdentifier = 0xff;
    packet.command = (byte)CommandTypes.SMB_COM_NEGOTIATE;
    packet.errorClass = 0xff;
    packet.error = 0;
    packet.flags = 0x00;
    packet.flags2 = 0x0001;
    packet.multiplexId = 22;
    packet.wordCount = 0;
    packet.byteCount = 119;

    packet.Buffer = "NT LM 0.12";

    MyPing.SendTo(It takes byte array as parameter);
}

Каков фрагмент кода был бы?

72
задан Peter Mortensen 18 January 2013 в 14:57
поделиться

5 ответов

Это довольно просто, используя маршалинг.

Начало файла

using System.Runtime.InteropServices

Функция

byte[] getBytes(CIFSPacket str) {
    int size = Marshal.SizeOf(str);
    byte[] arr = new byte[size];

    IntPtr ptr = Marshal.AllocHGlobal(size);
    Marshal.StructureToPtr(str, ptr, true);
    Marshal.Copy(ptr, arr, 0, size);
    Marshal.FreeHGlobal(ptr);
    return arr;
}

И чтобы преобразовать его обратно:

CIFSPacket fromBytes(byte[] arr) {
    CIFSPacket str = new CIFSPacket();

    int size = Marshal.SizeOf(str);
    IntPtr ptr = Marshal.AllocHGlobal(size);

    Marshal.Copy(arr, 0, ptr, size);

    str = (CIFSPacket)Marshal.PtrToStructure(ptr, str.GetType());
    Marshal.FreeHGlobal(ptr);

    return str;
}

В вашей структуре вам нужно будет поместить это перед строкой

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string Buffer;

И убедитесь, что SizeConst такой большой, как ваша самая большая возможная строка .

И вы, наверное, должны прочитать это: http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx

112
ответ дан 24 November 2019 в 12:32
поделиться

Взгляните на эти методы:

byte [] StructureToByteArray(object obj)
{
    int len = Marshal.SizeOf(obj);

    byte [] arr = new byte[len];

    IntPtr ptr = Marshal.AllocHGlobal(len);

    Marshal.StructureToPtr(obj, ptr, true);

    Marshal.Copy(ptr, arr, 0, len);

    Marshal.FreeHGlobal(ptr);

    return arr;
}

void ByteArrayToStructure(byte [] bytearray, ref object obj)
{
    int len = Marshal.SizeOf(obj);

    IntPtr i = Marshal.AllocHGlobal(len);

    Marshal.Copy(bytearray,0, i,len);

    obj = Marshal.PtrToStructure(i, obj.GetType());

    Marshal.FreeHGlobal(i);
}

Это бесстыдная копия другой ветки, которую я нашел в Google!

Обновление : Дополнительные сведения см. В источнике

22
ответ дан 24 November 2019 в 12:32
поделиться

Я бы посмотрел на классы BinaryReader и BinaryWriter. Недавно мне понадобилось сериализовать данные в байтовый массив (и обратно), и я нашел эти классы только после того, как практически переписал их сам.

http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx

На этой странице также есть хороший пример.

0
ответ дан 24 November 2019 в 12:32
поделиться

Вы можете использовать Marshal (StructureToPtr, ptrToStructure) и Marshal.copy, но это зависит от платформы.


Сериализация включает функции пользовательской сериализации.

public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 

SerializationInfo включает функции для сериализации каждого члена.


BinaryWriter и BinaryReader также содержат методы для сохранения / загрузки в массив байтов (поток).

Обратите внимание, что вы можете создать MemoryStream из байтового массива или байтового массива из MemoryStream.

Вы можете создать метод Save и метод New в своей структуре:

   Save(Bw as BinaryWriter)
   New (Br as BinaryReader)

Затем вы выбираете элементы для сохранения / загрузки в поток -> байтовый массив.

2
ответ дан 24 November 2019 в 12:32
поделиться

Похоже на предопределенную структуру (уровень C) для некоторой внешней библиотеки. Маршал - твой друг. Посмотрите:

http://geekswithblogs.net/taylorrich/archive/2006/08/21/88665.aspx

, чтобы узнать, как с этим справиться. Обратите внимание, что с помощью атрибутов вы можете определять такие вещи, как разметка байтов и обработка строк. ОЧЕНЬ хороший подход, на самом деле.

Для этого не используются ни BinaryFormatter, ни MemoryStream.

0
ответ дан 24 November 2019 в 12:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: