momo
momo

Reputation: 3474

Proper way of closing Streams in Java Sockets

I saw some posts about this but I still can't find an answer.

This is how my server interacts with the client:

public void run () {
    try {
        //Read client request
        InputStream is = server.getInputStream();
        byte[] buff = new byte[1024];
        int i;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((i = is.read(buff, 0, buff.length)) != -1) {
            bos.write(buff, 0, i);
            System.out.println(i + " bytes readed ("+bos.size()+")");
        }
        is.close();
        is = null;
        //Do something with client request

        //write response
        OutputStream os = server.getOutputStream();
        os.write("server response".getBytes());
        os.flush();
        os.close();
        os = null;

    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
}

And this is the client side:

public void run() {
        try {
            InetAddress serverAddr = null;
            serverAddr = InetAddress.getByName("10.0.2.2");
            socket = new Socket(serverAddr, 5000);

            //Send Request to the server
            OutputStream os = socket.getOutputStream();
            os.write(jsonRequest.toString().getBytes("UTF-8"));
            os.flush();
            os.close();
            os = null;

            //Read Server Response
            InputStream is = socket.getInputStream();
            byte[] buff = new byte[1024];
            int i;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while ((i = is.read(buff, 0, buff.length)) != -1) {
                bos.write(buff, 0, i);
                System.out.println(i + " bytes readed ("+bos.size()+")");
            }
            is.close();
            is = null;

            //Do something with server response

        } catch (UnknownHostException uhe) {
            sendCallbackError(uhe);
        } catch (IOException ioe) {
            sendCallbackError(ioe);
        }
    }

As you can see, the client connects and send a request. Server read that request then writes a response that the client will read.

The problem with this code is the OutputStream.close() in the client and InputStream.close() in the server. As stated in the Javadocs, closing the stream will close the Socket. The result is that when the client tries to read the server response, the Socket is already closed.

I've managed to overcome this by calling Socket.shutdownInput and Socket.shutdownOutput instead. However I am still thinking whether this is the proper way of doing it

As a note, closing the streams with close() when server writes the response or when the client reads it doesn't create problems (I would guess the closing is synchronized between client and server).

So my questions are:

  1. Is using the Socket shutdown methods a proper way?
  2. Can I keep closing the last streams with close() (when sending and reading response from server)
  3. Could it happen that closing with shutdown would keep some data in the buffer and wouldn't be sent?

Upvotes: 0

Views: 3146

Answers (2)

user207421
user207421

Reputation: 311048

The problem with this code is the OutputStream.close() in the client and InputStream.close() in the server. As stated in the Javadocs, closing the stream will close the Socket.

Correct but the InputStream in the server isn't connected directly to a Socket: it is connected to something you don't know anything about. You can close it with impunity, although again you don't need to close it at all. You can close the OutputStream in the server if you like: although, again, as it isn't connected directly to a Socket, it may or may not have any effect other than flushing.

To address your actual question, you don't need to close the output stream in the client, but you do need to send an appropriate Content-Length: header. That way the server knows how much to read from the client. If this is only a GET request the content-length may well be zero. You don't need to call shutdownOutput(), although I guess there is nothing to stop you, and calling shutdownInput() doesn't do anything to the network anyway so again there is no point to it.

Upvotes: 0

S.A.Norton Stanley
S.A.Norton Stanley

Reputation: 1873

You can do the following:

try{
}catch(){
}finally{
if(is!=null){
is.close();
}
if(os!=null){
os.close();
}
}

Upvotes: 1

Related Questions