C # Deserializar una estructura después de recibirla a través de TCP

Estoy enviando mi propio objeto struct “paquete” a través de la interfaz TCP que C # ofrece con TCPListener y TCPClient.

Esta es mi estructura

[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(); } } 

Estoy utilizando los métodos de serialización dentro de la estructura para preparar y recuperar los datos antes y después del envío.

Para que el receptor sepa el tamaño de los datos entrantes, agrego algunos datos de encabezado a los bytes que se envían, en el formato de l = 212; … lo que significa longitud = 212; y el es el rest del paquete.

En el extremo receptor, busco esto hasta que encuentre todo l = xxxx; luego hago una nueva matriz de bytes sin el encabezado, luego bash deserializar los datos. El byte de paquete que se utilizará para la deserialización es: buffer de tcp stream.Length – foundHeaderSize (l = xxxx;)

Si ejecuto el cliente y el servidor en la misma máquina, funciona sin errores, sin embargo, si tengo el cliente y el servidor en máquinas separadas, recibo excepciones y se bloquea.

La excepción tiene lugar cuando el paquete se está deserializando, diciendo:

* System.Runtime.InteropServices.SafeArrayTypeMismatchException Se ha producido una discrepancia entre el tipo de tiempo de ejecución de la matriz y el tipo sb registrado en los metadatos en System.Runtime.InteropServices.PtrToStructureHelper

Stacktrace: System.Runtime.InteropServices.PtrToStructureHelper (IntPtr ptr, Object structure, Boolean allowValueClasses) en System.Runtime.InteropServices.PtrToStructure (IntPtr ptr, Type structureType .. *

Estoy pidiendo ayuda para identificar la causa del problema. ¿No puedo hacerlo así con objetos que vinieron a través de la red?

En lugar de tener una cadena que represente la longitud de su paquete y luego reste por la longitud de la cadena para saber dónde comenzar a leer, debe implementar el prefijo de longitud adecuado. El prefijo de longitud combinado con un encabezado de datos le permitirá leer cada paquete de acuerdo con su tamaño, luego el encabezado de datos lo ayudará a determinar qué hacer con los datos.

El prefijo ordinario de longitud agrega un encabezado fijo a cada “paquete” que envía. Para crear este encabezado, convierta un entero (la longitud de sus datos) en bytes, lo que dará como resultado 4 bytes, luego agregará el encabezado de datos después de eso y también el rest del paquete (que es la información que desea enviar) .

Esto creará la siguiente estructura de paquete:

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

Leer un paquete es muy simple:

  1. Lea los primeros 4 bytes ( Length ), conviértalos y asígnelos a una variable entera.

  2. Lee el siguiente byte (el encabezado de datos) y ponlo en una variable.

  3. Lee x bytes en una matriz de bytes (donde x es el número entero que declaraste en el paso 1).

  4. Utilice el encabezado de datos del paso 2 para determinar qué hacer con sus datos (la matriz de bytes del paso 3).

En una de mis respuestas anteriores puede ver un ejemplo de lo que acabo de explicar anteriormente.

Los datos binarios serializados de una estructura pueden diferir según la plataforma y el sistema operativo. por ejemplo, diferente alineación, diferente tamaño de largo. Esa podría ser la razón por la cual su código funciona en la misma máquina, pero no en una máquina diferente.

Le sugiero que utilice una biblioteca como Google ProtoBuf (rápida) https://developers.google.com/protocol-buffers/docs/csharptutorial

o confíe en la serialización de objetos C # utilizando, por ejemplo, Serialización XML (lenta) https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx