¿Por qué mi socket de cliente no recibe lo que envía mi socket de servidor?

Utilizando un socket .NET de locking y transmisión, me estoy conectando a un servidor. Cada vez que leo pequeños trozos de datos, todo va bien y los datos se reciben en mi memoria intermedia:

using (var socket = new Socket(SocketType.Stream, ProtocolType.IP)) { socket.Connect(IPAddress.Parse("127.0.0.1"), 5000); byte[] buffer = new byte[BufferSize]; socket.Receive(buffer); // Here buffer doesn't always contain all data the server sent me? Console.WriteLine(Encoding.Default.GetString(buffer)); } 

Sin embargo, en algunos casos, no recibo todo lo que el servidor me envía. Los datos parecen estar cortados. ¿Cuál puede ser la causa de esto?

Esto está documentado en el método Receive() , énfasis mío:

El método de recepción lee los datos en el parámetro del búfer y devuelve la cantidad de bytes leídos con éxito . Puede llamar a Receive desde ambos sockets orientados a conexión y sin conexión.

Al ignorar el valor de retorno, no sabrá qué parte de su memoria intermedia realmente contiene datos relevantes. Dependiendo del protocolo utilizado, puede o no conocer la longitud del contenido por adelantado. Algunos protocolos proporcionan esta longitud, otros cierran la conexión cuando terminan, y otro puede usar un límite de mensaje.

Tendrá que mantener los datos recibidos en otro búfer y devolver o emitir todo el búfer de mensajes cuando no haya más datos disponibles o esperados. Esto se puede hacer así:

 int BufferSize = 1024; using (var socket = new Socket(SocketType.Stream, ProtocolType.IP)) { socket.Connect(IPAddress.Parse("127.0.0.1"), 5000); byte[] buffer = new byte[BufferSize]; string message = ""; int bytesReceived; do { bytesReceived = socket.Receive(buffer); message += Encoding.ASCII.GetString(buffer, 0, bytesReceived); } while (bytesReceived > 0); Console.WriteLine(message); } 

Los bytes recibidos son caracteres ASCII (tal como se definen en el protocolo inventado), por lo que cada byte recibido indica un carácter (no puede convertir caracteres Unicode multibyte parcialmente recibidos). Los bytes se convierten a una cadena y se anexan a la variable de message . El código se repite hasta que el servidor cierra la conexión.

Cuando se conoce el tamaño del mensaje de antemano, de nuevo, dependiendo del protocolo utilizado, puede crear un búfer de mensajes y copiar los datos allí en cada Receive() :

 // Received using another Receive() call int messageSize = 1234; int totalBytesReceived = 0; byte[] messageBuffer = new byte[messageSize]; byte[] buffer = new byte[BufferSize]; int bytesReceived; do { bytesReceived = socket.Receive(buffer); // Copy the receive buffer into the message buffer, appending after // previously received data (totalBytesReceived). Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived); totalBytesReceived += bytesReceived; } while (bytesReceived > 0); // This assumes the connection wasn't closed prematurely. Console.WriteLine(Encoding.ASCII.GetString(messageBuffer)); 

Esto, a su vez, puede ponerse en un método resuable:

 public byte[] ReceiveMessage(Socket socket, int messageSize) { byte[] messageBuffer = new byte[messageSize]; int bytesReceived = 0; int totalBytesReceived = 0; do { byte[] buffer = new byte[BufferSize]; // Receive at most the requested number of bytes, or the amount the // buffer can hold, whichever is smaller. int toReceive = Math.Min(messageSize - totalBytesReceived, BufferSize); bytesReceived = socket.Receive(buffer, toReceive, SocketFlags.None); // Copy the receive buffer into the message buffer, appending after // previously received data (totalBytesReceived). Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived); totalBytesReceived += bytesReceived; } while (bytesReceived > 0); if (totalBytesReceived < messageSize) { throw new Exception("Server closed connection prematurely"); } return messageBuffer; } 

NetworkStream el NetworkStream que envuelve un socket, pero tiene los mismos problemas de lectura que el socket mismo. Deberá supervisar el valor de retorno y seguir llamando a Read() hasta que haya recibido todos los bytes. Lo mismo ocurre con el TcpClient que tiene un método GetStream() , en cuyo valor de retorno también deberá continuar leyendo hasta que haya leído todos los datos .

    Intereting Posts