Me disculpo por esta larga publicación. Lo hice lo más pequeño posible mientras seguía transmitiendo el problema.Problema muy extraño al enviar datos a través de Sockets en C#
Ok, esto me está volviendo loco. Tengo un cliente y un programa de servidor, ambos en C#. El servidor envía datos al cliente a través de Socket.Send(). El cliente recibe los datos a través de Socket.BeginReceive y Socket.Receive. Mi pseudo protocolo es el siguiente: el servidor envía un valor de dos bytes (corto) que indica la longitud de los datos reales seguidos inmediatamente por los datos reales. El cliente lee los dos primeros byes de forma asincrónica, convierte los bytes en un corto, e inmediatamente lee tantos bytes desde el socket de forma síncrona.
Ahora esto funciona bien para un ciclo cada pocos segundos más o menos, pero cuando aumento la velocidad, las cosas se ponen raras. Parece que el cliente leerá aleatoriamente los datos reales cuando intente leer desde la longitud de dos bytes. A continuación, intenta convertir estos dos bytes arbitrarios en un corto que conduce a un valor completamente incorrecto, lo que provoca un bloqueo. El siguiente código es de mi programa, pero recortado para mostrar solo las líneas importantes. Método del lado del servidor
para enviar datos:
private static object myLock = new object();
private static bool sendData(Socket sock, String prefix, byte[] data)
{
lock(myLock){
try
{
// prefix is always a 4-bytes string
// encoder is an ASCIIEncoding object
byte[] prefixBytes = encoder.GetBytes(prefix);
short length = (short)(prefixBytes.Length + data.Length);
sock.Send(BitConverter.GetBytes(length));
sock.Send(prefixBytes);
sock.Send(data);
return true;
}
catch(Exception e){/*blah blah blah*/}
}
}
método del lado del cliente para recibir los datos: El código de servidor
private static object myLock = new object();
private void receiveData(IAsyncResult result)
{
lock(myLock){
byte[] buffer = new byte[1024];
Socket sock = result.AsyncState as Socket;
try
{
sock.EndReceive(result);
short n = BitConverter.ToInt16(smallBuffer, 0);
// smallBuffer is a 2-byte array
// Receive n bytes
sock.Receive(buffer, n, SocketFlags.None);
// Determine the prefix. encoder is an ASCIIEncoding object
String prefix = encoder.GetString(buffer, 0, 4);
// Code to process the data goes here
sock.BeginReceive(smallBuffer, 0, 2, SocketFlags.None, receiveData, sock);
}
catch(Exception e){/*blah blah blah*/}
}
}
para recrear el problema de forma fiable:
byte[] b = new byte[1020]; // arbitrary length
for (int i = 0; i < b.Length; i++)
b[i] = 7; // arbitrary value of 7
while (true)
{
sendData(socket, "PRFX", b);
// socket is a Socket connected to a client running the same code as above
// "PRFX" is an arbitrary 4-character string that will be sent
}
Al observar el código anterior, se puede determinar que el servidor enviará para siempre el número 1024, la longitud de los datos totales, incluido el prefijo, como un resumen (0x400) seguido de "PRFX" en ASCII binario seguido de un grupo de 7 (0x07). El cliente leerá los dos primeros bytes (0x400), interpretará que es 1024, almacena ese valor como n y luego lee 1024 byes de la secuencia.
Esto es de hecho lo que hace durante las primeras 40 o más iteraciones pero, espontáneamente, el cliente leerá los dos primeros byes e interpretará que son 1799, no 1024. ¡1799 en hex es 0x0707 que son dos 7 consecutivos! Esa es la información, no la longitud! ¿Qué pasó con esos dos bytes? Esto sucede con cualquier valor que puse en la matriz de bytes, simplemente elegí 7 porque es fácil ver la correlación con 1799.
Si todavía estás leyendo en este punto, aplaudo tu dedicación.
Algunas observaciones importantes:
- La disminución de la longitud de b aumentará el número de iteraciones antes de que ocurra el problema, pero no impide que se produzca el problema
- Adición de un retraso significativo entre cada iteración del bucle puede evitar que ocurra el problema
- Esto NO ocurre cuando se utiliza tanto el cliente como el servidor en el mismo host y se conecta a través de una dirección de bucle invertido.
Como he mencionado, ¡esto me está volviendo loco! Siempre puedo resolver mis problemas de programación, pero este me ha dejado perplejo por completo. Así que estoy aquí abogando por cualquier consejo o conocimiento sobre este tema.
Gracias.
Este es un problema que tuve en un momento. Intente leer los datos de la red en un ciclo while hasta que lea la cantidad de datos especificada en el parámetro "longitud" – Kurru
Reiniciando el 1024; por supuesto, podría fallar al leer el encabezado de 2 bytes –
@Marc - Quiero decir que al registrar el valor de retorno de Recibir, verá menos de 1024 en el caso de prueba dado si la red subyacente proporciona menos que todo el mensaje en uno Reciba. –