C# отправляют объекты структуры через сокет

я сделал немного чтения в программировании клиента/сервера в c#. я достаточно знаком с этим процессом для выяснения у следующего вопроса:

как я передаю объекты структуры через tcp/ip вместо просто строк?

мое приложение является сетевой игрой с возможностями чата. таким образом вместо того, чтобы просто передать текст, я хотел бы к imploy структуру данных или структуру класса, которая будет иметь два поля: i. тип пакета ii. данные для типа пакета

и я передал бы это при необходимости во время выполнения приложения, и декодировать объект данных в принимающем конце и помещать его, где это принадлежит.

Я не ищу код, просто некоторые идеи и поисковые операторы, которые я могу подать к Google, таким образом, я буду; имейте лучшее понимание.

я читал о serialisation/de сериализации, то, что он способ пойти?

спасибо.


я проверил сообщения, которые обнаружились как связанные темы, но все еще хотели бы дальнейшее руководство.


6
задан iTEgg 18 December 2009 в 17:07
поделиться

6 ответов

Вы можете создать NetworkStream на основе Socket и использовать любой механизм Stream для передачи ваших данных. Это переводит ваш вопрос на: Как я могу читать / записывать структуру из / в Stream.

Вы можете использовать сериализацию, а также BinaryWriter / BinaryReader. Для небольшой структуры (как вы описываете) я бы написал несколько специальных методов:

var netStream = new NetworkStream(clientSocket, true);
var writer = new BinaryWriter(netStream);

writer.Write(data.Value1);
writer.Write(data.Value2);

Для больших структур я бы рассмотрел вариант Cheeso Marshaling.

3
ответ дан 8 December 2019 в 05:21
поделиться

Если вам не нужны все возможности сериализации - если вы просто хотите записать структуру в массив байтов, рассмотрите класс Marshal.

Например, рассмотрим приложение tar на C #. Формат tar основан на 512-байтовых блоках, и первый блок в серии имеет регулярную структуру. В идеале приложение хочет просто преобразовать данные из файла на диске, прямо в структуру . Это делает метод Marshal.PtrToStructure . Вот структура.

    [StructLayout(LayoutKind.Sequential, Size=512)]
    internal struct HeaderBlock
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
        public byte[]   name;    // name of file. 

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   mode;    // file mode

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   uid;     // owner user ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   gid;     // owner group ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public byte[]   size;    // length of file in bytes

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public byte[]   mtime;   // modify time of file

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   chksum;  // checksum for header

        // ... more like that... up to 512 bytes. 

Тогда вот общий класс, который выполняет копирование.

internal class RawSerializer<T>
{
    public T RawDeserialize( byte[] rawData )
    {
        return RawDeserialize( rawData , 0 );
    }    

    public T RawDeserialize( byte[] rawData , int position )
    {
        int rawsize = Marshal.SizeOf( typeof(T) );
        if( rawsize > rawData.Length )
            return default(T);

        IntPtr buffer = Marshal.AllocHGlobal( rawsize );
        Marshal.Copy( rawData, position, buffer, rawsize );
        T obj = (T) Marshal.PtrToStructure( buffer, typeof(T) );
        Marshal.FreeHGlobal( buffer );
        return obj;
    }

    public byte[] RawSerialize( T item )
    {
        int rawSize = Marshal.SizeOf( typeof(T) );
        IntPtr buffer = Marshal.AllocHGlobal( rawSize );
        Marshal.StructureToPtr( item, buffer, false );
        byte[] rawData = new byte[ rawSize ];
        Marshal.Copy( buffer, rawData, 0, rawSize );
        Marshal.FreeHGlobal( buffer );
        return rawData;
    }
}

Вы можете использовать этот класс с любой структурой . Вы должны использовать LayoutKind.Sequential и ограничиться непреобразуемыми типами (в основном примитивами и их массивами), чтобы использовать этот подход. Это быстро и эффективно, с точки зрения кода, производительности и памяти, но он немного ограничен в том, как его можно использовать.

Получив массив байтов, вы можете передать его через NetworkStream или т. Д., А затем выполнить десериализацию с использованием того же класса на другом конце.

6
ответ дан 8 December 2019 в 05:21
поделиться

Сериализация - это самый простой способ, поскольку система поддерживает ее напрямую. Однако есть некоторые проблемы с производительностью с большими и сложными объектами. В вашем случае похоже, что сериализация - это путь. Если вы хотите что-то более низкого уровня, вы можете проверить BinaryWriter / BinaryReader, который позволяет вам выполнять работу самостоятельно.

5
ответ дан 8 December 2019 в 05:21
поделиться

Двоичная сериализация .NET, вероятно, будет самой быстрой готовой опцией, если предположить, что обе стороны механизма связи - это C # и могут загружать одну и ту же сборку, содержащую типы сообщений. Свертывание собственной сериализации, вероятно, вполне нормально, если ваши структуры очень простые. Просто определите свою структуру данных в классе, а также метод для ее преобразования в строку и из нее.

1
ответ дан 8 December 2019 в 05:21
поделиться

Вы на правильном пути, используя сериализацию объектов.

Одна вещь, о которой я еще не упоминал, - это то, что двоичные сериализаторы обычно создают меньше байтов для отправки через сокет, однако если вы используете сериализатор XML или JSON, а затем сжимаете результаты с помощью CompressionStream (GZipStream?), Прежде чем отправить его по сетевому потоку, вы можете получить даже меньшие размеры в зависимости от типа данных в вашем объекте (это лучше всего работает, когда у вас много строк).

Это займет больше процессорного времени для отправки и чтения сообщений, так что это компромисс, если вам нужно снизить требования к пропускной способности.

1
ответ дан 8 December 2019 в 05:21
поделиться

В конечном итоге да: вы говорите о сериализации. Это может принимать разные формы, особенно в .NET, но в конечном итоге вам нужно выбирать между:

  • текст или двоичный файл; прямой двоичный имеет тенденцию быть меньше текста, поскольку обычно требует меньшего анализа и т. д .; текст (xml, json и т. д.) обычно представлен в потоке как UTF8 (хотя возможна любая кодировка). Они в целом удобочитаемы, и, несмотря на то, что они более подробны, обычно могут быть довольно хорошо сжаты.
  • контракт против метаданных; Сериализаторы на основе контрактов фокусируются на представлении данных - предполагается, что другой конец конвейера понимает структуру, но не предполагается, что они совместно используют реализацию. Это имеет ограничения в том, что вы не можете внезапно ввести какой-то совершенно неожиданный подкласс, но делает его независимым от платформы. В отличие от этого, сериализаторы на основе метаданных отправляют информацию о типе в потоке (т.е. «это экземпляр My.Namespace.FooBar ). Это действительно упрощает работу, но редко работает между разными платформами (и часто не между версиями) - и вся эта информация о типах может быть подробной
  • ручным или автоматическим; факт: ручные сериализаторы часто могут быть наиболее эффективными с точки зрения пропускной способности, поскольку вы можете вручную настроить черт возьми, из потока - но это требует много усилий, и вам нужно понимать, много ли сериализации. Автоматические сериализаторы намного лучше подходят для общего использования (на самом деле: большинство сценариев). Избегайте ручного управления, если у вас нет выбора Автоматические сериализаторы справляются со всеми сложностями, связанными с заботой о различных типах данных и т. Д.

Подходы к ручному сериализатору включают (просто упоминая ключевое слово "сериализатор"): TextWriter , XmlWriter , IXmlSerializable , BinaryWriter , ISerializable . Вы не хотите этого делать ...

Сосредоточение внимания на автоматических сериализаторах:

               | Contract               | Metadata
===============+========================+===========================
  Text         | XmlSerializer          | SoapFormatter
               | DataContractSerializer | NetDataContractSerializer
               | Json.NET               |
---------------+------------------------+---------------------------
  Binary       | protobuf-net           | BinaryFormatter

Поскольку вы говорите о необработанных потоках, я бы предпочел двоичный сериализатор на основе контрактов - но тогда я написал protobuf-net , поэтому я могу быть предвзятым ;-p

Для сравнения с обычными стеками RPC:

  • "удаленное взаимодействие" использует BinaryFormatter
  • "asmx" веб-службы (включая WSE *) используйте XmlSerializer
  • WCF может использовать многие, чаще всего DataContractSerializer или NetDataContractSerializer ,
7
ответ дан 8 December 2019 в 05:21
поделиться
Другие вопросы по тегам:

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