How to read all of Inputstream in Server Socket JAVA
The problem you have is related to TCP streaming nature.
The fact that you sent 100 Bytes (for example) from the server doesn't mean you will read 100 Bytes in the client the first time you read. Maybe the bytes sent from the server arrive in several TCP segments to the client.
You need to implement a loop in which you read until the whole message was received.
Let me provide an example with DataInputStream
instead of BufferedinputStream
. Something very simple to give you just an example.
Let's suppose you know beforehand the server is to send 100 Bytes of data.
In client you need to write:
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();
}
Now, typically the data size sent by one node (the server here) is not known beforehand. Then you need to define your own small protocol for the communication between server and client (or any two nodes) communicating with TCP.
The most common and simple is to define TLV: Type, Length, Value. So you define that every message sent form server to client comes with:
- 1 Byte indicating type (For example, it could also be 2 or whatever).
- 1 Byte (or whatever) for length of message
- N Bytes for the value (N is indicated in length).
So you know you have to receive a minimum of 2 Bytes and with the second Byte you know how many following Bytes you need to read.
This is just a suggestion of a possible protocol. You could also get rid of "Type".
So it would be something like:
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();
}
The following code compiles and looks better. It assumes the first two bytes providing the length arrive in binary format, in network endianship (big endian). No focus on different encoding types for the rest of the message.
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();
}
}
}
Reading from an InputStream of a Socket
One simple solution looks like this:
StringBuilder sb = new StringBuilder();
int c;
while ( (( c = inputStream.read() ) >= 0) && (c != 0x0a /* <LF> */) ) {
if ( c != 0x0d /* <CR> */ ) {
sb.append( (char)c );
} else {
// Ignore <CR>.
}
}
return sb.toString();
This code keeps reading bytes until the end of a line (or the end of the stream) is found, signalled by the <LF>
.
We expect <CR><LF>
where <CR>
is part of the line separator, so we just ignore any <CR>
while collecting all other bytes.
reading inputstream of a socket
- If nothing is sent through the stream - there is nothing to read yet. Your reader is just waiting.
- It is emptied out only from the data you have received.
- You should have the
while(true)
loop which is trying to read the line from the stream. You do not have to check anything.
If the socket is closed at the second side, reader is reading null
. If the second side has exited without closing the socket, you get IOException
.
TCP/IP Client : best way to read multiple inputstreams from server
These statements force the stream to be closed as soon as at least 1 byte is sent.
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length() > 0) {
end = true;
}
As soon as the ack of 6 is received the connection is closed. If the ack is ignored, the response may be sent in multiple packets, the connection would close after the first packet is received.
You must be able to determine when the ack and the response have ended.
- If you know how many characters are in the ack and response, you could loop like the question you referred to. You will need a loop for the ack and one for the response.
- If you do not know the number of
characters, then you will have to look for special characters, like
end-of-line or end-of-file to know when the ack line ends and when
the server response ends. Look for a special character for the end of each message. A third possibility is to wait for aI agree with the comment below. Originally, I hesitated to add 3 in the list. This option would most likely be used to detect a problem with the communication channel. If the time expires, then the client would give up with an error condition, it would not continue to process as if everything were alright.
specific amount of time. When the time has expired, continue. This is not reliable over TCP, since data can be lost and resent. It may take more time than you allot for a response.
Related Topics
How to Check CPU and Memory Usage in Java
Using Hibernate's Scrollableresults to Slowly Read 90 Million Records
Regex Date Format Validation on Java
Fill' Unicode Characters in Labels
Retrieving the Inherited Attribute Names/Values Using Java Reflection
Difference Between Generic Type and Wildcard Type
How to Decode JSON with Unknown Field Using Gson
Maven Parent Pom VS Modules Pom
Why Can't Enum's Constructor Access Static Fields
Java for Loop Syntax: "For (T Obj:Objects)"
Get All of the Classes in the Classpath
Running Rmi Server, Classnotfound
Creating a Bundle Jar with Ant
Where to Find Source Code for Java.Lang Native Methods
Java - Best Way to Grab All Strings Between Two Strings? (Regex)
Can an Array Be Used as a Hashmap Key
Get the Indices of an Array After Sorting
Looking for an Example for Inserting Content into the Response Using a Servlet Filter