Il problema che hai è correlato alla natura di streaming TCP.
Il fatto che tu abbia inviato 100 byte (ad esempio) dal server non significa che leggerai 100 byte nel client la prima volta che leggi. Forse i byte inviati dal server arrivano in diversi segmenti TCP al client.
È necessario implementare un ciclo in cui leggi fino a quando l'intero messaggio non è stato ricevuto. Fammi fornire un esempio con DataInputStream
invece di BufferedinputStream
. Qualcosa di molto semplice da darti solo un esempio.
Supponiamo che tu sappia in anticipo che il server sia inviare 100 byte di dati.
Nel client devi scrivere:
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();
}
Ora, in genere la dimensione dei dati inviata da un nodo (il server qui) non è nota in anticipo. Quindi è necessario definire il proprio piccolo protocollo per la comunicazione tra server e client (o due nodi) che comunica con TCP.
Il più comune e semplice è definire TLV: tipo, lunghezza, valore. Quindi si definisce che ogni messaggio inviato al client viene fornito con:
- 1 byte che indica tipo (ad esempio, potrebbe anche essere 2 o altro).
- 1 byte (o altro) per la lunghezza del messaggio
- N byte per il valore (n è indicato in lunghezza).
Quindi sai che devi ricevere un minimo di 2 byte e con il secondo byte sai quanti byte seguenti devi leggere.
Questo è solo un suggerimento di un possibile protocollo. Potresti anche sbarazzarti del "tipo".
Quindi sarebbe qualcosa di simile:
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();
}
Il seguente codice compila e sembra migliore. Presuppone che i primi due byte forniscano la lunghezza arrivano in formato binario, in Network Endianship (Big Endian). Nessuna attenzione su diversi tipi di codifica per il resto del messaggio.
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();
}
}
}