First off forgive me if I am mistaken for how blocking works, to my understanding blocking will pause the thread until it is ready, for exsample when reading user input the program will wait until the user hits return.
My problem is that instead of waiting for data to become available it reads bytes with the value 0. Is there a way to block until data becoms available?
The method readBytes is called in a loop.
public byte[] readBytes(){
try{
//read the head int that will be 4 bytes telling the number of bytes that follow containing data
byte[] rawLen = new byte[4];
socketReader.read(rawLen);
ByteBuffer bb = ByteBuffer.wrap(rawLen);
int len = bb.getInt();
byte[] data = new byte[len];
if (len > 0) {
socketReader.readFully(data);
}
return data;
} catch (Exception e){
e.printStackTrace();
logError("Failed to read data: " + socket.toString());
return null;
}
}
If read() returned -1, the peer has disconnected. You aren't handling that case. If you detect end of stream you must close the connection and stop reading. At present you have no way of doing so. You need to reconsider your method signature.
You should use readInt() instead of those four lines of code that read the length. At present you are assuming have read four bytes without actually checking. readInt() will check for you.
This way also you will never get out of sync with the sender, which at present is a serious risk.
I want to use a single ObjectInputStream to read from a byte array, but I keep getting a StreamCorruptedException every time I start the program.
public void run(){
byte[] receiveBuffer = new byte[65535];
bIn = new ByteArrayInputStream(receiveBuffer);
try {
in = new ObjectInputStream(bIn);
} catch (IOException e1) {
e1.printStackTrace();
}
while(true){
try {
packetIn = new DatagramPacket(receiveBuffer, receiveBuffer.length);
sock.receive(packetIn);
Object o = in.readObject();
//do things with o
}
}
}
I'm just trying to initialize the ObjectInputStream to read from the byte array eventually, but it's throwing that exception even if I remove the while loop.
What am I doing wrong here?
If you take a look at the javadocs for the ObjectInputStream(InputStream) constructor, you'll see:
Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.
...
throws
StreamCorruptedException - if the stream header is incorrect
(emphasis added)
In other words, the constructor doesn't just record the InputStream reference you give it, it also reads from that object. In this case, that's a stream of all 0s.
You should defer creating the ObjectInputStream until you have the serialized data (or at least enough of it to read the header).
(In the interest of "teach a person to fish," I'll also note that any time a method/constructor throws an exception you don't expect, that method's javadocs are a good place to start for understanding its behavior. The javadocs for the JDK classes are usually pretty good.)
Ok, this is how object streams work and the solution that works everywhere.
Object stream data is preceded by a 4 byte 'magical' sequence AC ED 00 05. An ObjectInputStream will peek for this data at construction time rather than before the first read. And that's logical: one wants to be sure it is a proper stream before being too far in an application. The sequence is buffered by the ObjectOutputStream at construction time so that it is pushed on the stream at the first write. This method often leads to complexities in buffered situations or transferring via pipes or sockets. Fortunately, there is a just as simple as an effective solution to all these problems:
Flush the ObjectOutputStream immediately after construction!
ObjectOutputStream myStream = new ObjectOutputStream ( anotherStream );
myStream.flush();
In your case, you will have to use a ObjectOutputStream if you want to read from an ObjectInputStream
The stream protocol includes a stream header, which ObjectInputStream reads in the constructor. You have to defer creating the stream until you have received something:
sock.receive(packetIn);
try {
in = new ObjectInputStream(bIn);
Object o = in.readObject();
} catch (IOException e1) {
e1.printStackTrace();
}
I put a number of objects into the stream, then get byte array out of it and then read everything back. First two pieces of data arrive in good condition, then I get zeroes and then EOF exception. Why?
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject("abcdef");
objectOutputStream.writeInt(1);
objectOutputStream.writeObject(new byte[]{1,2,3,4,5,6,7,8});
objectOutputStream.writeInt(2);
objectOutputStream.writeObject(new byte[]{11,12,13,14,15,16,17,18});
objectOutputStream.close();
byte[] original = byteArrayOutputStream.toByteArray();
System.out.println(Arrays.toString(original));
byte[] b=new byte[8];
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(original));
String s= (String) objectInputStream.readObject(); // works fine
objectInputStream.readInt(); // works fine
objectInputStream.read(b); // why it reads zeroes instead of [1,2,3,4,5,6,7,8]?
System.out.println(Arrays.toString(b));
int length = objectInputStream.readInt(); // EOF unexpectedly reached, why?
objectInputStream.read(b);
}
catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Exception:
java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:375)
at java.io.ObjectInputStream$BlockDataInputStream.readInt(ObjectInputStream.java:2775)
at java.io.ObjectInputStream.readInt(ObjectInputStream.java:949)
I suspect that the first issue is that you need to close() your objectOutputStream. See the ObjectOutputStream documentation for examples.
As well as closing your buffered stream...
You want to have readInt() for each writeInt() (as you are doing) You also need to have readObject() for each writeObject().
If you don't read the same way your wrote, you can't expect it to make any sense.
You are doing
objectOutputStream.writeObject(new byte[]{1,2,3,4,5,6,7,8});
so you need to do
byte[] bytes = (byte[]) objectInputStream.readObject();
Have a look at how ObjectOutputStream handles arrays in writeObject (specifically, look at ObjectOutputStream.writeArray(). It writes an array marker byte (to know what kind of object is stored), then the array length and then the array elements themselves.
Long story short, you should read it back with readObject, not with plain read (unless you want to actually parse that stream of bytes yourself, not expecting your bytes to be retrieved as in the original byte array).
InputStream.read(byte[]) simply gets the raw stream of bytes and writes them in your buffer.
Moreover, the subsequent calls (other than mere read()s) are expected to fail because the pointer is not placed at the beginning of a data structure which the deserializer can understand.
Looking to read in some bytes over a socket using an inputStream. The bytes sent by the server may be of variable quantity, and the client doesn't know in advance the length of the byte array. How may this be accomplished?
byte b[];
sock.getInputStream().read(b);
This causes a 'might not be initialized error' from the Net BzEAnSZ. Help.
You need to expand the buffer as needed, by reading in chunks of bytes, 1024 at a time as in this example code I wrote some time ago
byte[] resultBuff = new byte[0];
byte[] buff = new byte[1024];
int k = -1;
while((k = sock.getInputStream().read(buff, 0, buff.length)) > -1) {
byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
resultBuff = tbuff; // call the temp buffer as your result buff
}
System.out.println(resultBuff.length + " bytes read.");
return resultBuff;
Assuming the sender closes the stream at the end of the data:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
while(true) {
int n = is.read(buf);
if( n < 0 ) break;
baos.write(buf,0,n);
}
byte data[] = baos.toByteArray();
Read an int, which is the size of the next segment of data being received. Create a buffer with that size, or use a roomy pre-existing buffer. Read into the buffer, making sure it is limited to the aforeread size. Rinse and repeat :)
If you really don't know the size in advance as you said, read into an expanding ByteArrayOutputStream as the other answers have mentioned. However, the size method really is the most reliable.
Without re-inventing the wheel, using Apache Commons:
IOUtils.toByteArray(inputStream);
For example, complete code with error handling:
public static byte[] readInputStreamToByteArray(InputStream inputStream) {
if (inputStream == null) {
// normally, the caller should check for null after getting the InputStream object from a resource
throw new FileProcessingException("Cannot read from InputStream that is NULL. The resource requested by the caller may not exist or was not looked up correctly.");
}
try {
return IOUtils.toByteArray(inputStream);
} catch (IOException e) {
throw new FileProcessingException("Error reading input stream.", e);
} finally {
closeStream(inputStream);
}
}
private static void closeStream(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Exception e) {
throw new FileProcessingException("IO Error closing a stream.", e);
}
}
Where FileProcessingException is your app-specific meaningful RT exception that will travel uninterrupted to your proper handler w/o polluting the code in between.
The simple answer is:
byte b[] = new byte[BIG_ENOUGH];
int nosRead = sock.getInputStream().read(b);
where BIG_ENOUGH is big enough.
But in general there is a big problem with this. A single read call is not guaranteed to return all that the other end has written.
If the nosRead value is BIG_ENOUGH, your application has no way of knowing for sure if there are more bytes to come; the other end may have sent exactly BIG_ENOUGH bytes ... or more than BIG_ENOUGH bytes. In the former case, you application will block (for ever) if you try to read. In the latter case, your application has to do (at least) another read to get the rest of the data.
If the nosRead value is less than BIG_ENOUGH, your application still doesn't know. It might have received everything there is, part of the data may have been delayed (due to network packet fragmentation, network packet loss, network partition, etc), or the other end might have blocked or crashed part way through sending the data.
The best answer is that EITHER your application needs to know beforehand how many bytes to expect, OR the application protocol needs to somehow tell the application how many bytes to expect or when all bytes have been sent.
Possible approaches are:
the application protocol uses fixed message sizes (not applicable to your example)
the application protocol message sizes are specified in message headers
the application protocol uses end-of-message markers
the application protocol is not message based, and the other end closes the connection to say that is the end.
Without one of these strategies, your application is left to guess, and is liable to get it wrong occasionally.
Then you use multiple read calls and (maybe) multiple buffers.
Stream all Input data into Output stream. Here is working example:
InputStream inputStream = null;
byte[] tempStorage = new byte[1024];//try to read 1Kb at time
int bLength;
try{
ByteArrayOutputStream outputByteArrayStream = new ByteArrayOutputStream();
if (fileName.startsWith("http"))
inputStream = new URL(fileName).openStream();
else
inputStream = new FileInputStream(fileName);
while ((bLength = inputStream.read(tempStorage)) != -1) {
outputByteArrayStream.write(tempStorage, 0, bLength);
}
outputByteArrayStream.flush();
//Here is the byte array at the end
byte[] finalByteArray = outputByteArrayStream.toByteArray();
outputByteArrayStream.close();
inputStream.close();
}catch(Exception e){
e.printStackTrace();
if (inputStream != null) inputStream.close();
}
Either:
Have the sender close the socket after transferring the bytes. Then at the receiver just keep reading until EOS.
Have the sender prefix a length word as per Chris's suggestion, then read that many bytes.
Use a self-describing protocol such as XML, Serialization, ...
Use BufferedInputStream, and use the available() method which returns the size of bytes available for reading, and then construct a byte[] with that size. Problem solved. :)
BufferedInputStream buf = new BufferedInputStream(is);
int size = buf.available();
Here is a simpler example using ByteArrayOutputStream...
socketInputStream = socket.getInputStream();
int expectedDataLength = 128; //todo - set accordingly/experiment. Does not have to be precise value.
ByteArrayOutputStream baos = new ByteArrayOutputStream(expectedDataLength);
byte[] chunk = new byte[expectedDataLength];
int numBytesJustRead;
while((numBytesJustRead = socketInputStream.read(chunk)) != -1) {
baos.write(chunk, 0, numBytesJustRead);
}
return baos.toString("UTF-8");
However, if the server does not return a -1, you will need to detect the end of the data some other way - e.g., maybe the returned content always ends with a certain marker (e.g., ""), or you could possibly solve using socket.setSoTimeout(). (Mentioning this as it is seems to be a common problem.)
This is both a late answer and self-advertising, but anyone checking out this question may want to take a look here:
https://github.com/GregoryConrad/SmartSocket
This question is 7 years old, but i had a similiar problem, while making a NIO and OIO compatible system (Client and Server might be whatever they want, OIO or NIO).
This was quit the challenge, because of the blocking InputStreams.
I found a way, which makes it possible and i want to post it, to help people with similiar problems.
Reading a byte array of dynamic sice is done here with the DataInputStream, which kann be simply wrapped around the socketInputStream. Also, i do not want to introduce a specific communication protocoll (like first sending the size of bytes, that will be send), because i want to make this as vanilla as possible. First of, i have a simple utility Buffer class, which looks like this:
import java.util.ArrayList;
import java.util.List;
public class Buffer {
private byte[] core;
private int capacity;
public Buffer(int size){
this.capacity = size;
clear();
}
public List<Byte> list() {
final List<Byte> result = new ArrayList<>();
for(byte b : core) {
result.add(b);
}
return result;
}
public void reallocate(int capacity) {
this.capacity = capacity;
}
public void teardown() {
this.core = null;
}
public void clear() {
core = new byte[capacity];
}
public byte[] array() {
return core;
}
}
This class only exists, because of the dumb way, byte <=> Byte autoboxing in Java works with this List. This is not realy needed at all in this example, but i did not want to leave something out of this explanation.
Next up, the 2 simple, core methods. In those, a StringBuilder is used as a "callback". It will be filled with the result which has been read and the amount of bytes read will be returned. This might be done different of course.
private int readNext(StringBuilder stringBuilder, Buffer buffer) throws IOException {
// Attempt to read up to the buffers size
int read = in.read(buffer.array());
// If EOF is reached (-1 read)
// we disconnect, because the
// other end disconnected.
if(read == -1) {
disconnect();
return -1;
}
// Add the read byte[] as
// a String to the stringBuilder.
stringBuilder.append(new String(buffer.array()).trim());
buffer.clear();
return read;
}
private Optional<String> readBlocking() throws IOException {
final Buffer buffer = new Buffer(256);
final StringBuilder stringBuilder = new StringBuilder();
// This call blocks. Therefor
// if we continue past this point
// we WILL have some sort of
// result. This might be -1, which
// means, EOF (disconnect.)
if(readNext(stringBuilder, buffer) == -1) {
return Optional.empty();
}
while(in.available() > 0) {
buffer.reallocate(in.available());
if(readNext(stringBuilder, buffer) == -1) {
return Optional.empty();
}
}
buffer.teardown();
return Optional.of(stringBuilder.toString());
}
The first method readNext will fill the buffer, with byte[] from the DataInputStream and return the amount bytes read this way.
In the secon method, readBlocking, i utilized the blocking nature, not to worry about consumer-producer-problems. Simply readBlocking will block, untill a new byte-array is received. Before we call this blocking method, we allocate a Buffer-size. Note, i called reallocate after the first read (inside the while loop). This is not needed. You can safely delete this line and the code will still work. I did it, because of the uniqueness of my problem.
The 2 things, i did not explain in more detail are:
1. in (the DataInputStream and the only short varaible here, sorry for that)
2. disconnect (your disconnect routine)
All in all, you can now use it, this way:
// The in has to be an attribute, or an parameter to the readBlocking method
DataInputStream in = new DataInputStream(socket.getInputStream());
final Optional<String> rawDataOptional = readBlocking();
rawDataOptional.ifPresent(string -> threadPool.execute(() -> handle(string)));
This will provide you with a way of reading byte arrays of any shape or form over a socket (or any InputStream realy). Hope this helps!
hello i have a basic client-server system running using java sockets.
my problem is, that an object that i send from the client to the server does not contain the correct data after it has been sent once.
the first time i send it, it arrives with the correct values, but when i send it another time with different values, it still arrives at the server with the same values as the first time. it also happens if i send a completely different instance of that class. it always arrives with the data, which have been sent the very first time.
when i try this with other objects like java.lang.String it seems to work.
the problematic class looks like this:
public class Vector3f implements Serializable {
private static final long serialVersionUID = 2838034155614698213L;
public float x, y, z;
}
i use objectinputstream and objectoutputstream on both the server and the client to send and receive objects.
let me know, if you need any more information about the system.
thanks!
My guess is that you're changing the values of the fields and then retransmitting the same object. The ObjectOutputStream will notice that it's already sent the original object, and just send a reference the second time.
You could avoid this by calling reset() on the ObjectOutputStream - but I'd be tempted to just use separate instances anyway, possibly even making the class immutable. (Public mutable fields are almost never a good idea.)
The best way in case of serialization you should convert the object into a byte array object and then write into the socket.
// Serialize to a file
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(object);
out.close();
// Serialize to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
out = new ObjectOutputStream(bos) ;
out.writeObject(object);
out.close();
// Get the bytes of the serialized object
byte[] buf = bos.toByteArray();
// Deserialize from a file
File file = new File("filename.ser");
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
// Deserialize the object
Object obj = (Object) in.readObject();
in.close();
// Get some byte array data
byte[] bytes = getBytesFromFile(file);
// see Reading a File into a Byte Array for the implementation of this method
// Deserialize from a byte array
in = new ObjectInputStream(new ByteArrayInputStream(bytes));
in.close();