El problema que tiene está relacionado con la naturaleza de transmisión de TCP.
El hecho de que haya enviado 100 bytes (por ejemplo) del servidor no significa que leerá 100 bytes en el cliente la primera vez que lea. Tal vez los bytes enviados desde el servidor llegan en varios segmentos TCP al cliente.
Debe implementar un bucle en el que lea hasta que se recibió todo el mensaje. Déjame proporcionar un ejemplo con DataInputStream
en vez de BufferedinputStream
. Algo muy simple de darte solo un ejemplo.
Supongamos que sabes de antemano que el servidor debe enviar 100 bytes de datos.
En el cliente debe escribir:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
while(!end)
{
int bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length == 100)
{
end = true;
}
}
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
Ahora, por lo general, el tamaño de datos enviado por un nodo (el servidor aquí) no se conoce de antemano. Luego, debe definir su propio protocolo pequeño para la comunicación entre el servidor y el cliente (o dos nodos) comunicándose con TCP.
El más común y simple es definir TLV: tipo, longitud, valor. Por lo tanto, define que cada mensaje enviado servidor al cliente viene con:
- 1 byte indicando tipo (por ejemplo, también podría ser 2 o lo que sea).
- 1 byte (o lo que sea) para la longitud del mensaje
- N bytes para el valor (n se indica en longitud).
Entonces, sabe que debe recibir un mínimo de 2 bytes y con el segundo byte sabe cuántos bytes siguientes necesita leer.
Esto es solo una sugerencia de un posible protocolo. También podría deshacerse del "tipo".
Entonces sería algo como:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
int bytesRead = 0;
messageByte[0] = in.readByte();
messageByte[1] = in.readByte();
int bytesToRead = messageByte[1];
while(!end)
{
bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length == bytesToRead )
{
end = true;
}
}
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
El siguiente código se compila y se ve mejor. Se supone que los dos primeros bytes que proporcionan la longitud llegan en formato binario, en la endianismo de red (Big Endian). No se centra en diferentes tipos de codificación para el resto del mensaje.
import java.nio.ByteBuffer;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
class Test
{
public static void main(String[] args)
{
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
Socket clientSocket;
ServerSocket server;
server = new ServerSocket(30501, 100);
clientSocket = server.accept();
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
int bytesRead = 0;
messageByte[0] = in.readByte();
messageByte[1] = in.readByte();
ByteBuffer byteBuffer = ByteBuffer.wrap(messageByte, 0, 2);
int bytesToRead = byteBuffer.getShort();
System.out.println("About to read " + bytesToRead + " octets");
//The following code shows in detail how to read from a TCP socket
while(!end)
{
bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length() == bytesToRead )
{
end = true;
}
}
//All the code in the loop can be replaced by these two lines
//in.readFully(messageByte, 0, bytesToRead);
//dataString = new String(messageByte, 0, bytesToRead);
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}