repeticion - salir de un for c#
Bucle hasta que la respuesta de TcpClient sea completamente leĆda (4)
En el cliente / servidor TCP que acabo de escribir genero el paquete que deseo enviar a una secuencia de memoria, luego tomo la longitud de esa secuencia y la uso como un prefijo al enviar los datos. De esta forma, el cliente sabe cuántos bytes de datos necesitará leer para un paquete completo.
He escrito un cliente y servidor TCP simple. El problema radica en el cliente.
Tengo problemas para leer toda la respuesta del servidor. Debo dejar que el hilo duerma para permitir que se envíen todos los datos.
He intentado varias veces convertir este código en un bucle que se ejecuta hasta que el servidor haya terminado de enviar datos.
// Init & connect to client
TcpClient client = new TcpClient();
Console.WriteLine("Connecting.....");
client.Connect("192.168.1.160", 9988);
// Stream string to server
input += "/n";
Stream stm = client.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(input);
stm.Write(ba, 0, ba.Length);
// Read response from server.
byte[] buffer = new byte[1024];
System.Threading.Thread.Sleep(1000); // Huh, why do I need to wait?
int bytesRead = stm.Read(buffer, 0, buffer.Length);
response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Response String: "+response);
client.Close();
Intenta repetir el
int bytesRead = stm.Read(buffer, 0, buffer.Length);
while bytesRead> 0. Es un patrón común para eso, como lo recuerdo. Por supuesto, no te olvides de pasar los parámetros adecuados para el búfer.
No conoce el tamaño de los datos que leerá, por lo que debe establecer un mecanismo para decidir. Uno es el tiempo de espera y otro está usando delimitadores.
En su ejemplo, usted lee los datos de solo una iteración (lectura) porque no establece el tiempo de espera para leer y usa el valor predeterminado que es "0" milisegundo. Entonces tienes que dormir solo 1000 ms. Obtiene el mismo efecto al usar el tiempo de recepción en 1000 ms.
Creo que usar la longitud de los datos como prefijo no es la solución real porque cuando el socket está cerrado por ambos lados y la situación de espera del tiempo de espera no puede manejarse correctamente, los mismos datos pueden enviarse al servidor y dejar que el servidor reciba una excepción. Utilizamos el prefijo y la secuencia de caracteres final y los datos de comprobación para después de cada lectura. Después de cada lectura, verificamos los datos para la secuencia de caracteres de inicio y fin, si no podemos obtener caracteres finales llamamos a otra lectura. Pero, por supuesto, esto funciona si tiene el control del lado del servidor y el código del lado del cliente.
La naturaleza de las transmisiones que se construyen sobre los sockets es que tiene una canalización abierta que transmite y recibe datos hasta que se cierra el socket.
Sin embargo, debido a la naturaleza de las interacciones cliente / servidor, esta canalización no siempre garantiza tener contenido para leer. El cliente y el servidor tienen que aceptar enviar contenido a través de la canalización.
Cuando toma la abstracción de Stream
en .NET y la superpone en el concepto de sockets, el requisito de un acuerdo entre el cliente y el servidor sigue siendo válido; puede llamar a Stream.Read
todo lo que quiera, pero si el socket al que está conectado su Stream
en el otro lado no está enviando contenido, la llamada solo esperará hasta que haya contenido.
Es por eso que existen los protocolos. En su nivel más básico, ayudan a definir qué es un mensaje completo que se envía entre dos partes. Por lo general, el mecanismo es algo así como:
- Un mensaje con prefijo de longitud donde se envía el número de bytes a leer antes del mensaje
- Un patrón de caracteres utilizado para marcar el final de un mensaje (esto es menos común dependiendo del contenido que se está enviando, cuanto más arbitraria sea cualquier parte del mensaje, es menos probable que se use)
Dicho esto, no estás adhiriendo a lo anterior; su llamada a Stream.Read
solo dice "leer 1024 bytes" cuando, en realidad, puede que no haya 1024 bytes para leer. Si ese es el caso, la llamada a Stream.Read
se bloqueará hasta que se haya completado.
La razón por la que la llamada a Thread.Sleep
probablemente funciona es porque cuando pasa un segundo, Stream
tiene 1024 bytes para leer y no bloquea.
Además, si realmente desea leer 1024 bytes, no puede suponer que la llamada a Stream.Read
1024 bytes de datos. El valor de retorno para el método Stream.Read
te dice cuántos bytes se leyeron realmente. Si necesita más para su mensaje, entonces necesita hacer llamadas adicionales a Stream.Read
.
Jon Skeet escribió la forma exacta de hacerlo si quieres una muestra.