C # десериализация структуры после ее получения через TCP

Я отправляю свой собственный объект struct «packet» через интерфейс TCP, который предлагает C # с помощью TCPListener и TCPClient.

Это моя структура

[Serializable] struct RemuseNetworkPacket { public String ApplicationCode; public String ReceiverCode; public RemusePacketType Type; public uint ID; public uint cID; public String Name; public byte[] Data; public String Text; public System.Drawing.Point Coords; public String Timestamp; public String Time; public String SenderName; public byte[] Serialize() { var buffer = new byte[Marshal.SizeOf(typeof(RemuseNetworkPacket))]; var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned); var pBuffer = gch.AddrOfPinnedObject(); Marshal.StructureToPtr(this, pBuffer, false); gch.Free(); return buffer; } public void Deserialize(byte[] data) { var gch = GCHandle.Alloc(data, GCHandleType.Pinned); this = (RemuseNetworkPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(RemuseNetworkPacket)); gch.Free(); } } 

Я использую методы сериализации внутри структуры для подготовки и получения данных до и после отправки.

Чтобы сообщить получателю информацию о размере входящих данных, я добавляю некоторые данные заголовка в отправляемые байты в формате l = 212; … что означает length = 212; и это остальная часть пакета.

На приемном конце я ищу это, пока не найду все l = xxxx; то я делаю новый массив байтов без заголовка, а затем пытаюсь десериализовать данные. Байт для использования для десериализации: буфер tcp stream.Length – foundHeaderSize (l = xxxx;)

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

Исключение происходит, когда пакет десериализуется, говоря:

* System.Runtime.InteropServices.SafeArrayTypeMismatchException Несоответствие произошло между типом среды выполнения и типом sb, записанным в метаданных в System.Runtime.InteropServices.PtrToStructureHelper

Stacktrace: System.Runtime.InteropServices.PtrToStructureHelper (IntPtr ptr, Структура объекта, Boolean allowValueClasses) в System.Runtime.InteropServices.PtrToStructure (IntPtr ptr, Тип структурыType .. *

Я прошу помочь определить причину проблемы. Не могу ли я сделать это с помощью объектов, которые попали по сети?

Вместо того, чтобы строка представляла вашу длину пакета и затем вычитала длину строки, чтобы узнать, где начать чтение, вы должны реализовать правильную длину-префикс . Префикс длины в сочетании с заголовком данных позволит вам читать каждый пакет в соответствии с его размером, тогда заголовок данных поможет вам определить, что делать с данными.

Обычная длина-префикс добавляет фиксированный заголовок к каждому отправленному вами «пакету». Чтобы создать этот заголовок, вы преобразуете целое число (длину ваших данных) в байты, что приведет к 4 байтам, после чего вы добавите заголовок данных после этого, а также оставшуюся часть пакета (это данные, которые вы хотите отправить) ,

Это создаст следующую структуру пакетов:

 [Length (4 bytes)][Header (1 byte)][Data (x byte(s))] 

Чтение пакета очень просто:

  1. Прочитайте первые 4 байта ( Length ), конвертируйте и назначьте их целочисленной переменной.

  2. Прочитайте следующий байт (заголовок данных) и поместите его в переменную.

  3. Чтение x байтов в массив байтов (где x – целое число, указанное на шаге 1).

  4. Используйте заголовок данных с шага 2, чтобы определить, что делать с вашими данными (массив байтов с шага 3).

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

Сериализованные двоичные данные структуры могут различаться в зависимости от платформы и ОС. например, различное выравнивание, разный размер длинных. Это может быть причиной того, что ваш код работает на одном компьютере, но не на другой машине.

Я предлагаю вам использовать библиотеку, например, Google ProtoBuf (быстрый) https://developers.google.com/protocol-buffers/docs/csharptutorial

или полагаться на сериализацию объектов C #, используя, например, XML-сериализацию (медленную) https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx

  • Возможно ли обновить коэффициент масштабирования окна tcp после трехстороннего рукопожатия, отправив syn / ack?
  • Поддерживает ли ServerSocket обратный сокет на произвольном порту?
  • Как обнаружить ближайший боковой разъем?
  • Почему открыт порт 1111, и безопасно ли быть?
  • close () не закрывает гнездо правильно
  • Содержит ли соединение сокетов TCP «поддерживать»?
  • Что означают номера, используемые в адресе IPV6?
  • Возможно ли, чтобы ПК одновременно использовал два сетевых соединения?
  • Может ли два приложения прослушивать один и тот же порт?
  • Создают ли браузеры новые TCP-соединения для каждого HTTP-запроса?
  • Найти следующий TCP-порт в .Net
  • Давайте будем гением компьютера.