I've been reading about Network IO for some time now. One of the questions I've had is- what is the scope of the data socket object that is returned as a result of the accept operation at the server.
Does the data socket remain alive even after the client that started the connection is no longer alive?
Also are there two sets of input and output streams? Input and output Streams at the client end of the connection, i.e associated with the socket object at the client ( the one the client creates to connect to the server) and the input, output streams at the server end of the other socket the server creates ( I believe the server creates another socket for each client socket request and this socket is different from the ServerSocket at the port the server is listening on). So what happens to each of these streams when the client is no longer alive in cases
1. when the client closes the streams.
2. when the client does not close the streams.
How about the streams at the server end? Are there 4 streams or are there two streams? I'd like to believe there are four streams but I don't know. If there are four streams, when and how are the streams at the server part of the connection closed?
Do we need to close the streams and sockets separately or does closing the socket closes everything. Further when the client is no longer alive, are the streams and socket automatically closed and eligible for garbage collection?
Are there any best practices in regards to closing the sockets and streams?
P.s - I am currently studying only the traditional blocking IO way to create network connections. So all of the above is with respect to the traditional way of network IO - not sure though if any of the above would change with the latest NIO package and libraries.
posted 7 years ago
Ok, actually I should also mention this.
Following is what I think a stream is.
In File IO -
Stream is like some sort of a container that can hold data ( in various formats - bytes, character, string, xml, URL, Objects .... and so on ). At one end of the stream, I have my program object. At the other end of it is the file. So when I say an input/output stream, input/output is with respect to my program object. So if I have an InputStream, my application object would read from it. If I have an OutputStream, my application object writes to it.
Is this analogy correct?
Applying this to Network IO, this is what I get.
At the client end - One end of it has the client object, other end has the socket. So InputStream means my client program reads from it. OutputStream means my client program writes to it.
At the server end - same but with respect to the server program object.
Yes, and through the magic of networking protocols, the input stream at the server end is "connected" to the output stream at the client end; and vice versa.
They are not physically connected, of course. The networking libraries provided by Java and the OS make them appear to be connected. Behind the scenes, whenever the client writes some bytes to the output stream, the underlying libraries split the data into chunks, wrap them in packets and send them over the wire to the ISP. The ISP unpacks them, packs them again and sends them to the next hop in the network. The packets keep hopping until they reach the server. The networking libraries on the server unpack the packets and join them in the right order and give the data to the server's output stream. When the server writes bytes to it's own output stream, the exact same process happens in reverse
As a programmer, you don't need to worry about the actual mechanics of how data travels between 2 sockets (although it;s a fascinating subject). You can just think of the inputstream at one end connected to outputsstream at the other end. Think of your telephone as an analogy. When you get a call, you pick up the phone and talk, whatever you speak into the mouthpiece can be heard in the earpiece of the other party. And whatever they speak in their mouthpiece can be heard in your ear piece. Both talkers on the phone linke think that their phones are "connected" although they are not physically connected (Actually long time ago they used to be physically connected, but let's not digress). Sockets work in very much same way. Outputstream at one end (mouthpiece) is connected to the Inputstream at other end(earpiece)
posted 7 years ago
Thanks, Jayesh, for that wonderful explanation. It helped me understand a lot of other things as well.
Now the part of my question that's unanswered is this-
Do I need to explicitly close all my sockets and/or streams? To be more precise, I have the following two scenarios.
Case 1: Following is the first variant, where my Server creates a separate Socket for each request that comes in. The sockets don't have to be short lived as there is no throttling the number of connections here. The code below is directly copied from the book, Java Threads, Edition 3. I have copied it here for the sole purpose of learning and understanding it - and it's still partial code.
In the client implementation for this server, I do not have a specific socket.close() instruction. There is no throttling the number of connections and hence the socket can be alive for as long as there can be requests and responses.
There is a second case, where the server throttles the number of connections that can be alive by maintaining a pool of threads that are listening on the server port. When the server starts up, it pre initializes and starts all these threads, passing them its own reference ( the server is a runnable ). The connections are accepted in the run method, and hence a socket is created by each thread in its run method.
In the client implementation, I perform the following many times.
Socket socket = new Socket( host, port );
// reading and writing
I understand this is because the sockets are supposed to be short lived here.
So do I conclude that we don't need to close the sockets explicitly, if the sockets are not supposed to be short lived. When the client is no longer alive, the socket and its streams would also go out of scope and will be eligible for garbage collection?
I think I may have found an answer ( a partial one ) to this question. I think sockets are just like any other Java objects. They would be eligible for garbage collection when there is no reference pointing to them.
The reason they should be closed as soon as the requirement is met is probably to ensure the server can reuse the socket. Since there is a limit on the number of sockets that can be created by the server, it is suggested they be closed as soon as they are no longer required. This becomes even more important when the client is running for a longer duration than the duration for which it requires the Socket.
So this may be the reason why there is no socket.close() instruction in the first case. Socket is active for as long as the client is active, sending repeated requests to the server.
On the server side, the shutdown method takes care of closing the socket and the associated streams.
Now the confusion is this.
1. socket.close() closes the associated streams. Then why do the Oracle tutorials say that the streams ( output, followed by input ) should be closed and then the socket should be closed.
2. If the client closes the socket, is the server socket, along with its streams, automatically closed, cause otherwise there is no point in closing the client socket as server still has the same limitation-- a socket is occupied/held and cannot be reused and the limitation is more at the server side.
Chan, it's a good idea to close the streams and sockets explicitly because it releases all the underlying OS resources immediately. If you don't close it explicitly, the resources will be released when GC evicts the object. However, since you have no control over when GC runs (or when it actually evicts your object), the underlying OS resources might be wasted. This applies to not only sockets, but all the Java API that is tied to an underlying OS resource. This is why Java 7 has introduced the new Closeable interface. If it's Closeable, it should be closed explicitly.
If you close the socket/stream at one end, without closing the socket/stream at the other end, any read/write operations on the open end will generally result in an exception. In some cases, data might be lost while it's on the way
This is why it's a good for the client and server to do a handshake when they connect, and a goodbye when they disconnect. Going back to the phone analogy. Let's say you are talking to your friend on the phone, and for some reason the friend suddenly put down the phone (could be anything:- the line got disconnected, he thought conversation was over, the cat stepped on the reciever, the baby is drowning in the bathtub, the house is on fire). Now, first thing you'd do is go "hello hello, are you there" right? and second thing you will do is get worried about him. You might make a mental note to check back with him later. Or you might even try calling him back to check. It would be much better instead if he says "Bye" or "Gotta go" or "TTYL" so you know that the conversation is over. Once you exchange goodbyes, he and and you both know that the phone has to be put down.
The same thing applies to sockets too. Let's say the client is done, and just closes the socket. The only way the server will know is by trying to read from the socket and catching an exception. some servers will just ignore the exceptions. SOme might log it. Some might crash Instead, if the client says good bye before closing the connection, server can close the connection as soon it gets the goodbye message
posted 7 years ago
underlying OS resources
Those are the magic words, I so needed to hear. Now everything ( ok, may be not everything- many things ) is (are) beginning to make sense, some of the file IO things as well.
I will read about the Closeable interface. Thanks for helping me. The problem with me is when I get stuck at some point, it is sort of difficult for me to move ahead with so many doubts and vague things in my mind.
I will also try to find more on what are the nice techniques to have the server and the client exchange the status information ( the handshakes and goodbyes ).
Also somebody at one another forum has responded on a similar question saying that the new try with resources addresses a lot of similar issues. So that is another to-check thing.