Das Problem, das Sie haben, bezieht sich auf die TCP -Streaming -Natur.
Die Tatsache, dass Sie 100 Bytes (zum Beispiel) vom Server gesendet haben, bedeutet nicht, dass Sie beim ersten Mal 100 Bytes im Client lesen. Vielleicht kommen die vom Server gesendeten Bytes in mehreren TCP -Segmenten an den Client an.
Sie müssen eine Schleife implementieren, in der Sie lesen, bis die gesamte Nachricht empfangen wurde. Lassen Sie mich ein Beispiel mit geben DataInputStream
Anstatt von BufferedinputStream
. Etwas sehr Einfaches, um Ihnen nur ein Beispiel zu geben.
Nehmen wir an, Sie wissen zuvor, dass der Server 100 Bytes Daten senden soll.
Im Kunden müssen Sie schreiben:
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();
}
In der Regel ist die Datengröße, die von einem Knoten (dem Server hier) gesendet wurde, vorher nicht bekannt. Anschließend müssen Sie Ihr eigenes kleines Protokoll für die Kommunikation zwischen Server und Client (oder zwei Knoten) definieren, die mit TCP kommunizieren.
Am häufigsten und einfachsten besteht darin, TLV zu definieren: Typ, Länge, Wert. Daher definieren Sie, dass jeder mit dem Meldung gesendete Formular Server an Client mit:
- 1 Byte angibt den Typ (zum Beispiel könnte es auch 2 oder was auch immer sein).
- 1 Byte (oder was auch immer) für die Länge der Nachricht
- N Bytes für den Wert (n ist in Länge angezeigt).
Sie wissen also, dass Sie mindestens 2 Bytes erhalten müssen, und mit dem zweiten Byte wissen Sie, wie viele folgende Bytes Sie lesen müssen.
Dies ist nur ein Vorschlag eines möglichen Protokolls. Sie können auch "Typ" loswerden.
Es wäre also so etwas wie:
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();
}
Der folgende Code kompiliert und sieht besser aus. Es wird angenommen, dass die ersten beiden Bytes, die die Länge im binären Format in Network Endianship (Big Endian) ankommen, angeben. Kein Fokus auf verschiedene Codierungstypen für den Rest der Nachricht.
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();
}
}
}