Generally, close() should only be done by the party responsible for open(). That way, the open-close pair can be managed easier. Since we can't open socket i/o streams (conceptually they are open as soon as socket is open), we should not close them. The party that opened the socket should close the socket though.
Sometimes you have no choice, you pass an open stream to a method, and the method decides it has the right to close the stream. You can pass a wrapper stream so that close() doesn't have effect.
If you really want to, you can close socket i/o streams without closing the socket, but they cannot be re-open once closed.
shutdownInput()
- pretty useless. If an application doesn't need any more input, simply stop reading - there is no point to invoke this method. Stop receiving data from peer. If the peer tries to send data to us, it may receive error ("connection reset")
shutdownOutput()
- can be very useful, it flushes all the data to the peer, and sends a FIN signal. The connection is now half-closed. The peer can still send data, and we can still read it, because that direction is still open.
These two methods are not used often. Normally Socket.close() is called to end the whole connection.