Java Socket closing OutputStream - java

I have always learned to always close a stream when I finish using it. Java 7 gives you a new option to do this (namely: try-with-resources), and it's all fine, except that when I close the OutputStream of a socket, the socket gets closed aswell. This is counter-productive, because I am using sockets in a streaming application.
So if I execute the code below, I understand the ObjectOutputStream gets closed after the try-block, and the socket's OutputStream gets closed too, which finally leads to closing my Socket.
try(ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
oos.writeObject(new MyDTO(data));
}
I could of course change my code to look like below, but everyone has always told me I should close my Streams when I finish using them. And this is just one method, but I have multiple other methods which also use the OutputStream and ObjectOutputStream to send data to my client(s).
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())
oos.writeObject(new MyDTO(data));
}
Do I have to expect other errors and misbehaviors as a result of not closing the ObjectOutputStream? I think it's nice that the socket is closed, when you have bursty-traffic applications, but it is kind-of weird when you're doing a streaming application.
What's the best practice? Teach me please.

Obviously if you still need the resources, you won't close them. The idea is to close them after you're done with them. If you're creating a chat software, you'd keep the connection open and the resources in use. However if you were to create some sort of poor man's FTP software, you might want to close the connection after the file has been transferred.
The try-with-resources is to make it easier to write code that is guaranteed to release its resources, which is often useful when dealing with streams, database connections and other such things. You don't have to use it everywhere, especially when it makes your work harder.

The question doesn't really make sense. You can't in practice create multiple ObjectOutputStreams over the same socket (and even if you know how to do it there is no advantage), so there is no reason to be using try-with-resources with the ObjectOutputStream in the first place. It should be created along with the socket, almost certainly stored as an instance member somewhere, and closed when you're finished with the connection.

Related

How can I serialize an object to a non-blocking socket in java

I have been reading about java nio and non-blocking sockets and I want to write serialized objects into the socket. I was reading this article here http://www.owlmountain.com/tutorials/NonBlockingIo.htm#_Toc524339525, and it says if you wrap your non-blocking socket around a PrintWriter, it will be blocking. I wonder if it's the same if I wrap my socket.getOutputStream around an ObjectOutputStream? Any easy way to test if a wrapper will be blocking or not? I couldn't find any mentions of this in the PrintWriter or ObjectOutputStream documentation.
Here' a code snippet from the article above:
else if ( key.isWritable() ) {
Socket socket = (Socket) key.attachment();
PrintWriter out = new PrintWriter( socket.getOutputStream(), true );
out.println( "What is your name? " );
}
Not sure if you missed it or not, but the article clearly says than any conventional I/O utilities used won't cut in and goes out to present the sample code for reading and writing text from asynchronous channels. Here is the relevant extract:
The problem with this code is that the
PrintWriter blocks I/O and does not
support the underlying asynchronous
I/O mechanisms. To deal with this
problem, we cannot use any of the
standard I/O utilities, but instead
must wrap our message in a ByteBuffer
object and send it through the
SocketChannel object
Is that code not working in your case?
You said:
I am trying to figure out how to
convert an object into a byte[].
Strings have the getBytes() method. I
am not sure what to use for a general
serializable Object. I have been using
ObjectOutput/InputStream classes but
according to the article, if I use
them, it will be blocking again. Am I
understanding this correctly?
You are correct; wrapping the I/O streams with ObjectInputStream/ObjectOutputStream would again end up blocking things. The solution here might be to wrap a ByteArrayOutputStream in an ObjectOutputStream and write your objects to the underlying byte array. This underlying byte stream/array now has the byte representation (which follows the Java serialization specification obviously) of your object. From there on, it's the normal stuff with NIO. In case you are interested, there are some nice discussions here and here related to the thing I'm talking about.
EDIT: Also, I agree with the article's author that NIO is tricky to get right. The author recommends Apache Mina but I'll like to add another recommendation, "Jboss Netty". The author of Netty frequents SO so you can get your queries answered.
I'd also like to point out that if your motivation is to send across Java objects, use a framework which is tuned to those needs i.e. Java RMI or JBoss remoting. Much easier than mucking around with object streams etc.

Do I need to close a ByteArrayInputStream?

Short question,
I saw in some old code where a ByteArrayInputStream was created like:
new BufferedReader(new InputStreamReader(new ByteArrayInputStream(somebytes)));
And then the BufferedReader is used to read out somebytes line by line.
All working fine, but I noticed that the BufferedReader is never closed.
This is all working in a long running websphere application, the somebytes are not terrible big (200k most), it is only invoked a few times a week and we're not experiencing any apparent memory leaks. So I expect that all the objects are successfully garbage collected.
I always (once) learned that input/output streams need to be closed, in a finally statement. Are ByteStreams the exception to this rule?
kind regards
Jeroen.
You don't have to close ByteArrayInputStream, the moment it is not referenced by any variable, garbage collector will release the stream and somebytes (of course assuming they aren't referenced somewhere else).
However it is always a good practice to close every stream, in fact, maybe the implementation creating the stream will change in the future and instead of raw bytes you'll be reading file? Also static code analyzing tools like PMD or FindBugs (see comments) will most likely complain.
If you are bored with closing the stream and being forced to handle impossible IOException, you might use IOUtils:
IOUtils.closeQuietly(stream);
It is always good practice to close your readers. However not closing a ByteArrayInputStream does not have as heavy of a potential negative effect because you are not accessing a file, just a byte array in memory.
As #TomaszNurkiewicz mentioned it's always good to close the opened stream. Another good way to let it do the try block itself. Use try with resource like.......
try ( InputStream inputStream = new ByteArrayInputStream(bytes); Workbook workBook = new XSSFWorkbook(inputStream)) {
here Workbook and InputStream both implements Closeable Interface so once try block completes ( normally or abruptly), stream will be closed for sure.
Resources need to be closed in a finally (or equivalent). But where you just have some bytes, no it doesn't matter. Although when writing, be careful to flush in the happy case.

How to safely cancel an InputStream read?

When reading from an InputStream, is there a way to cancel the read when it reaches a certain size and ignore the rest of the stream safely ensuring the resources are completely released?
So far, I just finish the read, but ideally I would like to stop reading it and move on. How do I do it safely?
Here is what I have so far:
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] byteData = new byte[16384];
while ((nRead = inputStream.read(byteData, 0, byteData.length)) != -1){
if(buffer.size() <= MAX_FILE_SIZE){
buffer.write(byteData, 0, nRead);
}
}
if(buffer.size() <= MAX_FILE_SIZE){
buffer.flush();
mData = buffer.toByteArray();
}
inputStream.close();
Thanks
Calling close() does what you want with respect to the JVM and its resources.
However, in some circumstances it could have effects that are undesirable. For instance, if the input stream is (ultimately) a socket stream, then closing the stream closes the socket, and take may cause the remote server that is sending data to see a network error. (This probably doesn't matter, but if it is not handled cleanly, you may well see exceptions in a remote webserver's logfile.)
Even if it was in the middle of being read and doesn't finish?
Yes. Any data that is "in flight" will be thrown away.
By closing its socket handle, this application says implicitly that it is no longer interested in the data.
Under normal circumstances1, there is nothing else that has the socket handle that allows it to read that data.
There is no way for anything else to reconnect to the socket. That is not supported by the socket APIs ... at the operating system level.
There is therefore no point in "keeping" the data.
(If we are talking about a socket stream then the remote server might get an exception if it tries to write more data to the socket after the close propagated. But even if that occurs, the remote server has no way of knowing how much data this end actually read before "pulling the plug" on the connection.)
Also, does the buffer need to be somehow cancelled or closed as well.
Since it is a ByteArrayOutputStream, No. Streams that read from / write to in-memory buffers (byte arrays, StringBuffers) don't need to be closed2. The GC can reclaim purely in-memory resources without any issues. Also a BufferedInput/OutputStream doesn't need to be closed if the stream it wraps doesn't need closing.
1 - I think it is possible for a Linux/Unix to open a socket, and pass it to a forked child process. However, it is impractical for both the parent and child processes to both use the socket because of the difficulty coordinating their use of it. Furthermore, you can't do this kind of thing between Java processes because the Java Process API doesn't allow it.
2 - The only hypothetical case where that is not true is when the buffer is a NIO Buffer backed by a shared memory segment or memory-mapped file ... which the garbage collector may be unable to reclaim in a timely fashion. And I say hypothetical because I don't think there are off-the-shelf stream wrappers for NIO Buffer objects.
close() is safe and does release resources: http://download.oracle.com/javase/6/docs/api/java/io/InputStream.html#close%28%29
That is all that you need to do on this end. It releases all JVM resources. If it's associated with a socket, this socket will be closed. Operating system (IOW transport layer) will simply discard all buffers, forthcoming packets etc. The other end of the connection (sender) may see an error, but either way it should be prepared for it.

Have you ever seen a Java File close() throw an exception?

Has anyone ever seen an exception thrown when calling close method on any closable object?
An IOException will be thrown on close if the final flush fails. Possible causes include:
the file system is full, or the user is over quota,
hard disc errors,
a file system was forcibly unmounted,
a remote file system is unavailable due to networking or other problems,
(possibly) a character encoding error if writing to the file via an OutputStreamWriter or similar,
a device error if the "file" is a device file,
a lost connection if the closeable is a network stream,
a broken pipe if the closeable is a pipe to external process,
and so on.
I have certainly seen some of these. Others are unlikely.
However, if the data you are writing is important then you should allow for close failing. For example, if your application is writing out a critical file the file system fills up, your application had better notice this before it replaces the old copy of the file with the truncated version.
Yes, it's not that rare, IMHO if you are working with anything other than non-local disk files.
Close() works if at that point your closable is still valid and open. Many things like pipes, remote files, etc., can die prematurely.
In addition, I have seen code that ignores errors on open and write and still tries to close (e.g., in a finally block).
Not in terms of file-io, but in terms of sockets the close will raise IOException when the other side has aborted the connection. For example, when you fire a HTTP request on a (large) webpage and then immediately navigate away by clicking another link on the webpage (while it isn't finished loading), then the server side will get an IOException (or a subclass like ClientAbortException in Tomcat servers and clones) when the outputstream of the HTTP response is to be flushed/closed.
Old post and long since answered but here's a real example:
The following code will except out when bufferedWriter.close() is called. This happens because the BufferedWriter's underlying Writer (the FileWriter) has already been closed and when a BufferedWriter closes, it first attempts to flush any data in its buffer to its underlying Writer.
File newFile = new File("newFile.txt");
FileWriter fileWriter = new FileWriter(newFile);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("Hello World");
fileWriter.close();
bufferedWriter.close();
Note: If there's no data in the buffer [comment out the write() line or add a flush() call] then no exception will be generated
I haven't, but it's possible. Imagine if there's an OutputStream that for some reason hasn't written to the file yet. Well, calling close() will flush out the data, but if the file is locked - then an IOException would be raised.
Try yanking a USB drive with an open file on it. If it doesn't give an exception I'd be pretty surprised.
I guess you could try to force this by unplugging the disk your file is on. But on any Closable? I think it would be easy to get something that uses a socket to throw an exception upon closing.
I have - in my unit tests against mocks ;)

Does closing the BufferedReader/PrintWriter close the socket connection?

I have an application that uses simple sockets to pass some characters between two systems. I have my java application running as a server. I establish a connection fine, and even pass one message. However, after one message has been sent my connection closes.
From what I can tell it appears as if on closing the printWriter and bufferedReader the socket itself is being closed?! This is bad, as I have multiple messages to send on the same connection.
printWriter = new PrintWriter(theServer.getClientSocket().getOutputStream());
bufferedReader = new BufferedReader(new InputStreamReader(theServer.getClientSocket().getInputStream()));
printWriter.println("the line");
printWriter.close(); //Closing on these lines?
bufferedReader.close(); //Closing on these lines?
Am I full of it? How do I maintain this connection in Java?
Yes, closing any Writer/Reader will close all other Writers and Readers that they wrap. Don't close it until you are ready to close the underlying socket.
As #Eddie said (seconds before me! :) ), closing the writer and/or the reader will close the underlying socket streams and the socket itself: However, I believe the socket itself will not be closed.
Closing the returned InputStream will close the associated socket.
You shouldn't close the writer nor the reader. Just flush the writer to make sure your messages will arrive in time. Closing the socket later on will close the respective streams, so you don't need to close them yourself. Just leave your reader/writer objects to the GC.
Another alternative is to create yourself a NoCloseInputStream and NoCloseOutputStream filters which simply do nothing on close; then use them to wrap your application socket's streams (before any application wrappering like a buffer).
Note that if you were to do this, you would need to keep a reference to the socket (or the wrapped streams) so that you can close the socket when you are actually done with it.
To answer the comment that this is "too advanced a concept for the OP": The OP's problem is that in closing the top level stream, he is also closing the underlying socket, but that's no good since he wants to create further top-level streams over the socket to send further messages. Depending on his architecture, the only way to achieve this may be to wrap the streams in NoClose wrappers - for example he may be passing the streams to an XML serializer or deserializer which closes the stream when it's done, which close is outside of his control.
You need to close the socket after closing the streams.

Categories

Resources