Read from InputStream causes OutOfMemoryError - java

My app connects to a Wi-Fi peripheral. I’m using Socket.getInputStream() and Socket.getOutputStream() to read/write data. When the connection is established I store these two streams so that I can reuse them as long as I’m connected. My app sends a command via the OutputStream every second and reads the result from the InputStream by its read() method. After some time I get an "OutOfMemoryError".
Correct me if I’m wrong but I think this is because read() does not remove the read data from the InputStream, right?
My question is: Is it a good practice to store the Streams? Or should I use Socket.getInputStream(), Socket.getOutputStream() every time I send a new command?
It seems not to be a problem with the OutputStream since I can call flush() for that.
What about reset() of InputStream? Does this remove the data for the stream?
Here is the code how I encapsulate my Streams:
#Override
public InputStream getInputStream() throws IOException {
return _Socket.getInputStream();
}
#Override
public OutputStream getOutputStream() throws IOException {
return _Socket.getOutputStream();
}
#Override
public void connect() throws IOException {
try {
SocketAddress socketAddress = new InetSocketAddress(_ip, _port);
_Socket = new Socket(_ip, _port);
} catch (IOException e) {
MyExceptionHandler.appendLog(MyExceptionHandler.exceptionToString(e));
throw e;
}
}
The code for sending and receiving commands comes from this api:
https://github.com/pires/obd-java-api/blob/master/src/main/java/com/github/pires/obd/commands/ObdCommand.java
The exception does also not come immediately. It occurs after ~30 Minutes and a lot of commands sent/received

Correct me if I’m wrong but I think this is because “read()” does not remove the read data from the InputStream, right?
Wrong. If you're running out of memory it's not because of InputStream. You have a bug in your code.
My question is: Is it a good practice to store the Streams?
Yes.
Or should I use “Socket.getInputStream(), Socket.getOutputStream() every time I send a new command?
No.
What about “reset()” of InputStream? Removes this the data for the stream?
No, it does what it says in the Javadoc.
EDIT The code you have linked to is at first inspection a load of rubbish. It never checks for end of stream for example, so when that happens it will read forever, accumulating 0xff bytes and eventually filling up memory. Find something better.

Related

Java pattern for subsequent Input & OutputStream

Hello stack overflow world, I've been struggling with the most straight forward and common problem within Java IO, for some time, and now need your help to tackle it.
Check out this piece of code I have in a try block, within a thread.run():
// connect to client socket, and setup own server socket
clientSocket = new Socket(serverHostname, CLIENT_PORT);
//send a test command to download a file
String downloadFileName = "sample.txt";
DataOutputStream dataOutputStream = new DataOutputStream(clientSocket.getOutputStream());
System.out.println("Sending a request to download file : " + downloadFileName + " from user: Arsa node"); //todo: replace with node user later
dataOutputStream.writeUTF("D/sample.txt");
//close socket if host isn't detected anymore, and if socket doesn't become null suddenly
dataOutputStream.flush();
dataOutputStream.close();
System.out.println("****File has been sent****");
in = new DataInputStream(clientSocket.getInputStream());
byte[] retrievedFileData = new byte[8036];
if (in.readInt() > 0) {
System.out.println("Starting file download!");
in.read(retrievedFileData);
System.out.println("File data has been read, converting to file now");
//closing input stream will close socket also
in.close();
}
clientSocket.close();
2 Main questions that have been confusing me to death:
Why does dataOutputStream.close() need to be run for writeUTF to actually send my string to the server socket, I find that when I don't have dos.close(), data isn't retrieved on the other side, further because I close it, I no longer can read from the socket - as it seems the socket connection becomes closed when the Output Stream is previously closed...
What's a better way, following some sort of pattern to do this? For context, all I'm trying to do is write the filename I'm looking to download to my client, then read the response right away, which I expect to be bytes with the file, any error handling I will consider as a part of my development.
Overall, it shouldn't be complicated to write something to a socket, then read and ingest it's response...which doesn't seem to be the case here,
any help would be greatly appreciated! If the ServerSocket code snippet is needed I'm happy to share.
The observed behavior is just a side-effect of close(), as it calls flush() before closing to make sure any buffered data is sent. To solve your problem, you need to call the flush() method instead of closing.
This behavior is not unique to DataOutputStream: a lot of other OutputStream (or Writer) implementations apply buffering, and you will need to flush when you want to ensure the data is sent to the client, written to disk or otherwise processed.
BTW: The DataOutputStream and DataInputStream is for a very specific type of data serialization protocol that is particular to Java. You may want to consider carefully if this is the right protocol to use.

How do I check if a client's socket InputStream contains data?

I want to check if the InputStream buffer contains any data which it can read and output without having to initially call readLine() and waiting for data.
I have looked into available() but this didn't seem to work as it always output 0.
while (true)
{
fromServer = in.readLine(); //Causing a hang waiting for reply
System.out.println(fromServer);
if ((fromUser = stdIn.readLine()) != null)
{
out.println(fromUser);
fromServer = in.readLine();
System.out.println(fromServer);
}
}
available() might tell you the number of bytes available, if implemented, but nothing can tell you whether there is a complete line other than trying to read it.
You need to read in a separate thread.
The issue is readLine() causes the client to get stuck hanging for a server reply if access isn't permitted for the client.
So the issue is really that the server should send something 'if access isn't permitted for the client', i.e. a message that says so, rather than doing nothing. You can't use absence of a message as a message in a blocking I/O system.
You also need to check every readLine() result for null, and if you get it when reading a socket you need to close it.
Create a new Instance of BufferedInputStream and call available on that object:
InputStream is = ...;
BufferedInputStream bis = new BufferedInputStream(inputStream);
if (bis.available() == 0) {
// do sth if input is available
}
I tried it with a little server-client application, it worked for me.
EDIT: Type mismatch gone.
As the Java Documentation says, the InputStream.available() always returns zero. In comparison to that, the BufferedInputStream returns „the number of bytes remaining that can be read in the buffer“

How can you force a flush on an OutputStream object without closing it?

My question lies on the following assumptions which I hope are true, because I believe these as I read them while Googling my problems:
Closing a Socket's OutputStream closes the socket too
The flush() method of OutputStream does nothing
So I basically need to anyhow flush the data out of my OutputStream object for my app to work.
If you're interested in details then please see the following two links :
. Weird behavior : sending image from Android phone to Java server (code working)
This issue was resolved by closing the OutputStream. Doing that flushed all the data to the other end of the socket and made my app working further but this fix soon gave rise to problem number 2 - the corresponding socket also gets closed :
. SocketException - 'Socket is closed' even when isConnected() returns true
You can call the flush method of OutputStream instead of close. The concrete classes inheriting from OutputStream will override flush() to do something other than nothing (writing the data to a file or sending it over the network).
The flush() method of OutputStream does nothing.
This is incorrect.
It is true that the base implementation of flush() provided by the OutputStream class does nothing. However, your app will be calling the version of that method that is provided by actual stream class that you are using. If the stream class doesn't have direct write semantics, it will override flush() to do what is required.
In short, if a flush is required (and it is required for a Socket output stream), then calling flush() will do the right thing. (If some internet source tells you otherwise it is either wrong or you are misinterpreting it.)
FYI, the reason that the base OutputStream implements flush() as a no-op is that:
some output stream classes don't need to do anything when flushed; e.g ByteArrayOutputStream, and
for the stream classes where flush() is not a no-op, there is no way to implement the operation at the base class level.
They could (in theory) have made designed the stream APIs so that OutputStream was an abstract class (and flush() an abstract method) or an interface. However this API was effectively frozen prior to Java 1.0, and at that time there wasn't enough experience with practical Java programming to realize that the API design was suboptimal.
Closing a Socket's OutputStream closes the socket too
True.
The flush() method of OutputStream does nothing
False. There are overrides. See the Javadoc for FilterOutputStream.flush(), BufferedOutputStream.flush(), ObjectOutputStream.flush(), to name a few.
So your initial problem is non-existent, so you have no need for the 'solution' that causes problem #2.
I'll take a stab at it. I was having the same problem. closing the outputstream is the only way i can "flush" the data. but since i still need the outputstream that's not an option. so 1st i send the byte array length, out.writeInt, then the array itself. when all bytes have been read ie buffer.length == in.readInt() i break loop
ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
byte[] fileBytes;
int n;
int length;
try
{
size = in.readInt();
while((n = in.read(buffer)) != -1)
{
dataBuffer.write(buffer, 0, n);
if(dataBuffer.toByteArray().length == length)
{
fileBytes = dataBuffer.toByteArray(); break;
}
}
}
I had the same problem.
Add "\n" at the end of the stream. flush works but the destinary does not know if the message ended
YES on Android flush() do nothing (example based on api 23)
public Socket() {
this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
this.proxy = null;
}
public class PlainSocketImpl extends SocketImpl {
#Override protected synchronized OutputStream getOutputStream() throws IOException {
checkNotClosed();
return new PlainSocketOutputStream(this);
}
}
private static class PlainSocketOutputStream extends OutputStream {
// doesn't override base class flush();
}
to flush output stream without closing socket you can shutdown output:
protected void shutdownOutput() throws IOException
-- this will close WRITE file descriptor.
instead of using output stream you can write directly to file descriptor or by creating own Socket implementation with OutputStream which will override flush method (for example using a Berkeley socket implementation in c (via native call).
Do you really need to flush? I also had an issue, where listener on c# server couldn't receive data sent from android (I tried to get the data synchronously).
I was sure that this is because on Android side, the following code didn't flush.
OutputStream str = btSocket.getOutputStream();
str.write(data_byte);
// "This implementation does nothing"
str.flush();
It turned out, that if I use asynchronous data retrieval on server's listener - it gets the data, and no flush() on client's side is required!

Problem with Sending and Receiving Files with SPP over Bluetooth

I am attempting to transfer files (MP3s about six megabytes in size) between two PCs using SPP over Bluetooth (in Java, with the BlueCove API). I can get the file transfer working fine in one direction (for instance, one file from the client to the server), but when I attempt to send any data in the opposite direction during the same session (i.e., send a file from the server to the client), the program freezes and will not advance.
For example, if I simply:
StreamConnection conn;
OutputStream outputStream;
outputStream = conn.openOutputStream();
....
outputStream.write(data); //Data here is an MP3 file converted to byte array
outputStream.flush();
The transfer works fine. But if I try:
StreamConnection conn;
OutputStream outputStream;
InputStream inputStream;
ByteArrayOutputStream out = new ByteArrayOutputStream();
outputStream = conn.openOutputStream();
inputStream = conn.openInputStream();
....
outputStream.write(data);
outputStream.flush();
int receiveData;
while ((receiveData = inputStream.read()) != -1) {
out.write(receiveData);
}
Both the client and the server freeze, and will not advance. I can see that the file transfer is actually happening at some point, because if I kill the client, the server will still write the file to the hard drive, with no issues. I can try to respond with another file, or with just an integer, and it still will not work.
Anyone have any ideas what the problem is? I know OBEX is commonly used for file transfers over Bluetooth, but it seemed overkill for what I needed to do. Am I going to have to use OBEX for this functionality?
It could be as simple as both programs stuck in blocking receive calls, waiting for the other end to say something... try adding a ton of log statements so you can see what "state" each program is in (ie, so it gives you a running commentary such as "trying to recieve", "got xxx data", "trying to reply", etc), or set up debugging, wait until it gets stuck and then stop one of them and single step it.
you can certainly use SPP to transfer file between your applications (assuming you are sending and receiving at both ends using your application). From the code snippet it is difficult to tell what is wrong with your program.
I am guessing that you will have to close the stream as an indication to the other side that you are done with sending the data .. Note even though you write the whole file in one chunk, SPP / Bluetooth protocol layers might fragment it and the other end could receive in fragments, so you need to have some protocol to indicate transfer completion.
It is hard to say without looking at the client side code, but my guess, if the two are running the same code (i.e. both writing first, and then reading), is that the outputStream needs to be closed before the reading occurs (otherwise, both will be waiting for the other to close their side in order to get out of the read loop, since read() only returns -1 when the other side closes).
If the stream should not be closed, then the condition to stop reading cannot be to wait for -1. (so, either change it to transmit the file size first, or some other mechanism).
Why did you decide to use ByteArrayOutputStream? Try following code:
try {
try {
byte[] buf = new byte[1024];
outputstream = conn.openOutputStream();
inputStream = conn.openInputStream();
while ((n = inputstream.read(buf, 0, 1024)) > -1)
outputstream.write(buf, 0, n);
} finally {
outputstream.close();
inputstream.close();
log.debug("Closed input streams!");
}
} catch (Exception e) {
log.error(e);
e.printStackTrace();
}
And to convert the outputStream you could do something like this:
byte currentMP3Bytes[] = outputStream.toString().getBytes();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(currentMP3Bytes);

java.io.StreamCorruptedException: invalid stream header: 7371007E

I have a client Server application which communicate using objects.
when I send only one object from the client to server all works well.
when I attempt to send several objects one after another on the same stream I get
StreamCorruptedException.
Can some one direct me to the cause of this error?
client write method
private SecMessage[] send(SecMessage[] msgs)
{
SecMessage result[]=new SecMessage[msgs.length];
Socket s=null;
ObjectOutputStream objOut =null;
ObjectInputStream objIn=null;
try
{
s=new Socket("localhost",12345);
objOut=new ObjectOutputStream( s.getOutputStream());
for (SecMessage msg : msgs)
{
objOut.writeObject(msg);
}
objOut.flush();
objIn=new ObjectInputStream(s.getInputStream());
for (int i=0;i<result.length;i++)
result[i]=(SecMessage)objIn.readObject();
}
catch(java.io.IOException e)
{
alert(IO_ERROR_MSG+"\n"+e.getMessage());
}
catch (ClassNotFoundException e)
{
alert(INTERNAL_ERROR+"\n"+e.getMessage());
}
finally
{
try {objIn.close();} catch (IOException e) {}
try {objOut.close();} catch (IOException e) {}
}
return result;
}
server read method
//in is an inputStream Defined in the server
SecMessage rcvdMsgObj;
rcvdMsgObj=(SecMessage)new ObjectInputStream(in).readObject();
return rcvdMsgObj;
and the SecMessage Class is
public class SecMessage implements java.io.Serializable
{
private static final long serialVersionUID = 3940341617988134707L;
private String cmd;
//... nothing interesting here , just a bunch of fields , getter and setters
}
If you are sending multiple objects, it's often simplest to put them some kind of holder/collection like an Object[] or List. It saves you having to explicitly check for end of stream and takes care of transmitting explicitly how many objects are in the stream.
EDIT: Now that I formatted the code, I see you already have the messages in an array. Simply write the array to the object stream, and read the array on the server side.
Your "server read method" is only reading one object. If it is called multiple times, you will get an error since it is trying to open several object streams from the same input stream. This will not work, since all objects were written to the same object stream on the client side, so you have to mirror this arrangement on the server side. That is, use one object input stream and read multiple objects from that.
(The error you get is because the objectOutputStream writes a header, which is expected by objectIutputStream. As you are not writing multiple streams, but simply multiple objects, then the next objectInputStream created on the socket input fails to find a second header, and throws an exception.)
To fix it, create the objectInputStream when you accept the socket connection. Pass this objectInputStream to your server read method and read Object from that.
when I send only one object from the client to server all works well.
when I attempt to send several objects one after another on the same stream I get StreamCorruptedException.
Actually, your client code is writing one object to the server and reading multiple objects from the server. And there is nothing on the server side that is writing the objects that the client is trying to read.
This exception may also occur if you are using Sockets on one side and SSLSockets on the other. Consistency is important.

Categories