ObjectOutputStream is causing memory leak and reset() throws error - java

This problem really has me stumped. I'm sending images from a client to a server using ObjectOutputStream, but over time the java heap keeps growing. This eventually causes an OutOfMemoryError exception. After some online research, the reset method seems to be the only solution. Which is great, but using it causes an error: mark/reset not supported. The only page I could find on this was here:
https://stackoverflow.com/questions/38814424/how-can-i-get-an-objectinputstream-that-supports-mark-reset
I'm not really sure what to do with that page's answer.
Anyway, here's the server code:
ServerSocket vchatserver = new ServerSocket(6677);
Socket c1 = vchatserver.accept();
ObjectInputStream ois = new ObjectInputStream(c1.getInputStream());
while(c1.isConnected()) {
ImageIcon icon = (ImageIcon) ois.readUnshared();
ois.reset();
}
And now the client's code:
Socket vchatclient = new Socket(pub_serverName, 6677);
ObjectOutputStream oos = new ObjectOutputStream(vchatclient.getOutputStream());
while(vchatclient.isConnected()) {
ImageIcon img = new ImageIcon(webcam.getImage());
oos.writeUnshared(img);
oos.reset();
Thread.sleep(25);
}

The object input stream doesn't support mark/reset. But you don't need it. You don't need to call reset() on the input stream. ObjectOutputStream.reset() is sufficient.
The question you linked is irrelevant.
NB while (c1.isConnected()) is not a valid test for end of stream. You need to catch EOFException. Similarly while (vchatclient.isConnected()) will not protect you from IOExceptions when writing. This method only tells you whether you have ever connected this socket. It doesn't tell you anything about the current state of the connection.

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.

StreamCorruptedException with heavy data over ObjectInputStream

I have a server-client setup over TCP where the client is sending a number of data sets to the server. The reading/writing uses ObjectInput/OutputStream. I don't have any problems under normal conditions, but when the data flow gets heavy, I get a StreamCorruptedException: invalid type code. The invalid code is different every time. I open the socket once and call a synchronized method to send data from multiple threads.
Client:
socket = new Socket("localhost", sockNum);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
public synchronized void sendMsg(Message msg){
try{
out.writeObject(security.signObject(msg, privKey));
out.reset();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Server:
ServerSocket server = new ServerSocket(sockNum);
Socket client = server.accept();
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
while(threadActive){
Object line = in.readObject();
handleObject(line);
}
Update: I added out.reset() after each send, but that didn't help the problem. I've also added sleep statments in my loop to decrease the data rate. This gets rid of the error but is not a real solution.
Edit: So it's been a little while since I originally asked this, but I'm running into the problem again. I tried setting up my system so that after every sent message, the thread waits for an "acknowledge" message in return. If the receiving process has the StreamCorruptedException, it sends back a "resend" rather than an ack. This seems to be causing more problems than solutions. Any other ideas?
It sounds like you are writing to the output stream in a multi threaded way i.e. you are writing to it somewhere other than in your example.
BTW: Are you reset()ing the stream regularly to prevent a memory leak?

java Exception: connection reset by peer: socket write error

I'm trying to invoke a method from another class that means I want to use serialization I make an object of method name and it's parameters and write it on a socket but when I want to make ObjectOutputStream I encounter with error "connection reset by peer: socket write error"
I searched for the possible reasons but I couldn't find any suitable answer
in the server side I didn't close the sockets or I didn't do any work to close that I don't know what happens then :-??
in the line:
ObjectOutputStream oos = (new ObjectOutputStream(os));
and my piece of code is this:
InvocationVO invo = new InvocationVO("showStart", treasure, round);
for (int i = 0; i < numPlayer; i++) {
OutputStream os = socket.get(i).getOutputStream();
ObjectOutputStream oos = (new ObjectOutputStream(os)); // this has error
oos.writeObject(invo);
oos.close();
os.close();
Client.getClients()[i].invoke();
}
thanks for your helps in advance!
You are writing to a connection that has already been closed by the peer. I find it hard to believe that didn't turn up in your search. The cause of the problem is firstly that you are closing oos, and therefore the socket, in this code, so (a) it won't run the second time, and (b) closing the socket causes the peer to get an EOS condition and close the socket, so (c) the second time you run this code you will run into at least two problems.
There is a third problem you haven't hit yet. You are creating a new ObjectOutputStream every time you run this code rather than using the same one for the life of the socket. Same goes for ObjectInputStream wherever you use it too. If you do what you are doing here you are liable to run into StreamCorruptedException: invalid type code.

jvm_bind problem when downloading through java

i have written the following code to download file.
java.io.BufferedInputStream in =
new java.io.BufferedInputStream(new java.net.URL(url).openStream());
java.io.FileOutputStream fos = new java.io.FileOutputStream(filename);
java.io.BufferedOutputStream bout = new BufferedOutputStream(fos,1024);
byte[] data = new byte[1024];
int x=0;
while((x=in.read(data,0,1024))>=0)
{
bout.write(data,0,x);
}
if(filename.equalsIgnoreCase("table.csv"))
{
updateflag=true;
}
if(filename.equalsIgnoreCase("quotes.csv"))
{
quoteupdate=true;
}
bout.flush();
bout.close();
in.close();
Now, when a file named "table.csv" is passed as paramenter to download function, everything works smooth. Problem is when i try to download "quotes.csv" after i download "table.csv".
The exact calling is this:
url="http://ichart.finance.yahoo.com/table.csv? s=%5EBSESN&a=00&b=31&c=2011&d="+(month-1)+"&e="+day+"&f="+year+"&g=d&ignore=.csv";
updateflag=true;
downloadDB("table.csv",url);
System.out.print("quotes to download");
url="http://download.finance.yahoo.com/d/quotes.csv?
s=%5EBSESN&f=sl1d1t1c1ohgv&e=.csv";
if(candownload==true)
{
downloadDB("quotes.csv",url);
}
candownload=false;
I get error saying : Unrecognized Windows Socket error:0: JVM_BIND
Now i understand JVM_BIND is saying i have a process already attached to port 80.
However, i have closed all streams at the end of my function. Why is this happening then?
Thanks in advance
I don't have enough privileges to post comments so my apologies for providing an answer that may not get to the exact problem.
Leaving streams open won't necessarily cause this problem AFAIK. It's really caused by trying to bind a new Server Socket when one is already existing. So... maybe you should check to see if your code is trying to bind a new ServerSocket every time (with the same port) the download function is called. You really shouldn't need to do that. Bind once, and in the accept method spawn a new thread that does the download.

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);

Categories