in.close() closes out's socket -- is this a bug?

Discussion in 'Java' started by Duane Evenson, Jul 3, 2009.

  1. I have buffered input and output streams going to a socket. When I close
    the input stream, it closes the socket without first flushing the output
    buffer.

    Should it do this? I would expect it to close the streams, but
    leave the socket alone. The following code demonstrates this problem.
    Invert the order of in.close() and out.close() and the program works.

    Here is my test code:
    Run this program by executing the code then running "telnet localhost
    8080"

    import java.io.*;
    import java.net.*;

    public class TestFlush2 {
    public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket(8080);
    Socket clientSocket = serverSocket.accept();
    BufferedOutputStream out = new BufferedOutputStream(
    clientSocket.getOutputStream());
    BufferedReader in = new BufferedReader(new InputStreamReader(
    clientSocket.getInputStream()));
    out.write("good output test string\n".getBytes("US-ASCII"));
    in.close();
    if(clientSocket.isClosed())
    System.out.println("clientSocket is closed by in.close");
    out.close();
    clientSocket.close();
    serverSocket.close();
    System.out.println("Done");
    }
    }
     
    Duane Evenson, Jul 3, 2009
    #1
    1. Advertising

  2. On Fri, 03 Jul 2009 13:58:11 -0600, Duane Evenson wrote:

    > I have buffered input and output streams going to a socket. When I close
    > the input stream, it closes the socket without first flushing the output
    > buffer.
    >
    > Should it do this? I would expect it to close the streams, but
    > leave the socket alone. The following code demonstrates this problem.
    > Invert the order of in.close() and out.close() and the program works.
    >
    > Here is my test code:
    > Run this program by executing the code then running "telnet localhost
    > 8080"
    >
    > import java.io.*;
    > import java.net.*;
    >
    > public class TestFlush2 {
    > public static void main(String[] args) throws IOException {
    > ServerSocket serverSocket = new ServerSocket(8080);
    > Socket clientSocket = serverSocket.accept();
    > BufferedOutputStream out = new BufferedOutputStream(
    > clientSocket.getOutputStream());
    > BufferedReader in = new BufferedReader(new InputStreamReader(
    > clientSocket.getInputStream()));
    > out.write("good output test string\n".getBytes("US-ASCII"));
    > in.close();
    > if(clientSocket.isClosed())
    > System.out.println("clientSocket is closed by in.close");
    > out.close();
    > clientSocket.close();
    > serverSocket.close();
    > System.out.println("Done");
    > }
    > }

    I'm using Java(TM) SE Runtime Environment (build 1.6.0_06-b02) on a Linux
    2.6.20 system.
     
    Duane Evenson, Jul 3, 2009
    #2
    1. Advertising

  3. Duane Evenson

    Lew Guest

    Duane Evenson wrote:
    > I have buffered input and output streams going to a socket. When I close
    > the input stream, it closes the socket without first flushing the output
    > buffer.
    >
    > Should it do this? I would expect it to close the streams, but
    > leave the socket alone. The following code demonstrates this problem.
    > Invert the order of in.close() and out.close() and the program works.


    Have you considered reading the documentation?
    <http://java.sun.com/javase/6/docs/api/java/net/Socket.html#getInputStream()>
    > Closing the returned InputStream will close the associated socket.


    --
    Lew
     
    Lew, Jul 3, 2009
    #3
  4. Duane Evenson

    Roedy Green Guest

    On Fri, 03 Jul 2009 13:58:11 -0600, Duane Evenson
    <> wrote, quoted or indirectly quoted someone who
    said :

    >I have buffered input and output streams going to a socket. When I close
    >the input stream, it closes the socket without first flushing the output
    >buffer.


    It is supposed to close the socket as a side effect of closing either
    the input or OutputStream. What is does with unsent data is not
    documented; at least I did not see it. I presume if you want it sent,
    you must do a flush first.
    --
    Roedy Green Canadian Mind Products
    http://mindprod.com

    "Out of 135 criminals, including robbers and rapists, 118 admitted that when they were children they burned, hanged and stabbed domestic animals."
    ~ Ogonyok Magazine 1979.
     
    Roedy Green, Jul 4, 2009
    #4
  5. Duane Evenson

    markspace Guest

    Roedy Green wrote:
    > On Fri, 03 Jul 2009 13:58:11 -0600, Duane Evenson
    > <> wrote, quoted or indirectly quoted someone who
    > said :
    >
    >> I have buffered input and output streams going to a socket. When I close
    >> the input stream, it closes the socket without first flushing the output
    >> buffer.

    >
    > It is supposed to close the socket as a side effect of closing either
    > the input or OutputStream. What is does with unsent data is not
    > documented; at least I did not see it. I presume if you want it sent,
    > you must do a flush first.



    That's pretty counter intuitive that a close does not flush. Hmm, maybe
    due to latency issues networks were implemented this way. You don't
    want to flush if the operation is going to stall indefinitely, just cut
    off data and recover resources.

    And I'm thinking about the TCP/IP stack in general here, not just the
    way Java has implemented it. Java just might be calling a lower level,
    native, API, which does not flush. Have to think about that though.


    Morale: socket streams do not act like file streams.
     
    markspace, Jul 4, 2009
    #5
  6. Duane Evenson

    markspace Guest

    Duane Evenson wrote:
    > I have buffered input and output streams going to a socket. When I close
    > the input stream, it closes the socket without first flushing the output
    > buffer.
    >
    > Should it do this? I would expect it to close the streams, but
    > leave the socket alone. The following code demonstrates this problem.
    > Invert the order of in.close() and out.close() and the program works.



    Oh, I think I see.

    Or rather, do you expect to be able to close input, but still use
    output? If so...

    Use shutdownInput(), not close(). This program below uses the same
    order as you do, but in.close() is replaced by a call to
    shutdownInput(). Now the client gets the write. (And my example
    doesn't need telnet, just run it, you'll see both ends of the
    connection. ;) Yes, this is one file -- note only one public class.
    Just cut and paste into your IDE.



    package fubar;

    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.logging.Level;
    import java.util.logging.Logger;


    public class TestFlush2 {

    static final int PORT = 12345;

    public static void main(String[] args)
    {
    new Thread( new TestFlushServer() ).start();
    try
    {
    Thread.sleep(200); // wait a bit for server to come up
    } catch (InterruptedException ex) { }
    new Thread( new TestFlushClient() ).start();
    }
    }


    class TestFlushServer implements Runnable {
    public void run()
    {
    try
    {
    ServerSocket serverSocket =
    new ServerSocket(TestFlush2.PORT);
    Socket clientSocket = serverSocket.accept();
    BufferedOutputStream out = new BufferedOutputStream(
    clientSocket.getOutputStream());
    BufferedReader in = new BufferedReader(
    new InputStreamReader(
    clientSocket.getInputStream()));
    out.write("good output test string\n".getBytes("US-ASCII"));
    // in.close();
    clientSocket.shutdownInput();
    if (clientSocket.isClosed())
    {
    System.out.println(
    "clientSocket is closed by in.close");
    }
    out.close();
    clientSocket.close();
    serverSocket.close();
    System.out.println("Server Done");
    } catch (IOException ex)
    {
    Logger.getLogger(TestFlushServer.class.getName())
    .log(Level.SEVERE, null, ex);
    ex.printStackTrace();
    }
    }
    }


    class TestFlushClient implements Runnable
    {
    public void run()
    {
    try
    {
    Socket sock = new Socket("localhost", TestFlush2.PORT);
    BufferedReader input = new BufferedReader(
    new InputStreamReader(
    sock.getInputStream(), "US-ASCII" ) );
    String s;
    while( (s = input.readLine()) != null )
    {
    System.out.println("CLIENT: "+s);
    }
    sock.close();
    System.out.println("CLIENT: done");
    } catch (UnknownHostException ex)
    {
    Logger.getLogger(TestFlushClient.class.getName())
    .log(Level.SEVERE, null, ex);
    } catch (IOException ex)
    {
    Logger.getLogger(TestFlushClient.class.getName())
    .log(Level.SEVERE, null, ex);
    }
    }

    }
     
    markspace, Jul 4, 2009
    #6
  7. Duane Evenson

    Roedy Green Guest

    On Fri, 03 Jul 2009 18:01:07 -0700, markspace <>
    wrote, quoted or indirectly quoted someone who said :

    >That's pretty counter intuitive that a close does not flush. Hmm, maybe
    >due to latency issues networks were implemented this way. You don't
    >want to flush if the operation is going to stall indefinitely, just cut
    >off data and recover resources.


    There is need for both an abort and a close function. Maybe it works
    like this: They could have invented an abort method alternate to
    close. But they made close behave like abort, and flush-close like
    close, so all methods were available inside the usual InputStream
    interface.

    --
    Roedy Green Canadian Mind Products
    http://mindprod.com

    "Out of 135 criminals, including robbers and rapists, 118 admitted that when they were children they burned, hanged and stabbed domestic animals."
    ~ Ogonyok Magazine 1979.
     
    Roedy Green, Jul 4, 2009
    #7
  8. Duane Evenson

    Lew Guest

    markspace wrote:
    > That's pretty counter intuitive that a close does not flush. Hmm, maybe
    > due to latency issues networks were implemented this way. You don't
    > want to flush if the operation is going to stall indefinitely, just cut
    > off data and recover resources.
    >
    > And I'm thinking about the TCP/IP stack in general here, not just the
    > way Java has implemented it. Java just might be calling a lower level,
    > native, API, which does not flush. Have to think about that though.
    >
    >
    > Morale: socket streams do not act like file streams.


    I don't see any indication in
    <http://java.sun.com/javase/6/docs/api/java/io/FileOutputStream.html#close()>
    that it flushes, either.

    I don't think this is limited to Java.

    The documentation for 'FilterOutputStream#close()', the parent class for
    'BufferedOutputStream' among others, makes a point of specifying that it
    flushes, hinting that the omission from the docs for 'FileOutputStream' is not
    arbitrary.

    Now, before someone gets hyper, I realize that 'FileOutputStream#write()' is
    unbuffered and normally doesn't need to flush, but the lack of such a promise
    means that it is free to use non-sync system calls to do its dirty work, or to
    do internal buffering on its own, and we'd have no right to complain if a
    sudden 'close()' left some written things hanging.

    --
    Lew
     
    Lew, Jul 4, 2009
    #8
  9. Duane Evenson

    markspace Guest

    Lew wrote:

    >
    > I don't see any indication in
    > <http://java.sun.com/javase/6/docs/api/java/io/FileOutputStream.html#close()>
    >
    > that it flushes, either.
    >
    > I don't think this is limited to Java.


    FileOutputStream basically just calls close0(), a private native method.
    So it's behavior seems platform dependent, or at least liable to vary
    in details a bit.

    So I guess the moral here (did I actually write "morale?" Geeze...) is
    to not assume too much when reading the API docs.
     
    markspace, Jul 4, 2009
    #9
  10. On Fri, 03 Jul 2009 17:57:14 -0700, Roedy Green wrote:

    > On Fri, 03 Jul 2009 13:58:11 -0600, Duane Evenson
    > <> wrote, quoted or indirectly quoted someone who
    > said :
    >
    >>I have buffered input and output streams going to a socket. When I close
    >>the input stream, it closes the socket without first flushing the output
    >>buffer.

    >
    > It is supposed to close the socket as a side effect of closing either
    > the input or OutputStream. What is does with unsent data is not
    > documented; at least I did not see it. I presume if you want it sent,
    > you must do a flush first.


    I'd assumed the socket stayed open since in all the Sun Java tutorials,
    the use out.close();in.close();socket.close();. Why bother to
    explicitly close the socket if it was closed with the first command? The
    documentation says closing a stream releases the resources, but I would
    assume that only meant releasing that resource for that stream -- call it
    a semi-release -- not that resource for ALL streams.

    I think it's a design flaw to close the socket if other steams are still
    associated with that socket.
     
    Duane Evenson, Jul 4, 2009
    #10
  11. Duane Evenson

    Lew Guest

    Roedy Green wrote:
    >> It is supposed to close the socket as a side effect of closing either
    >> the input or OutputStream. What is does with unsent data is not
    >> documented; at least I did not see it. I presume if you want it sent,
    >> you must do a flush first.


    Duane Evenson wrote:
    > I'd assumed the socket stayed open since in all the Sun Java tutorials,
    > the use out.close();in.close();socket.close();. Why bother to


    The Javadocs explicitly state that closing the socket input or output stream
    closes the socket.

    > explicitly close the socket if it was closed with the first command? The


    The tutorials may not serve as good templates to follow slavishly, or perhaps
    they want to promote a consistency of approach that applies to all I/O, not
    just sockets. One can only guess absent asking the tutorial author.

    > documentation says closing a stream releases the resources, but I would
    > assume that only meant releasing that resource for that stream -- call it
    > a semi-release -- not that resource for ALL streams.


    You keep talking about what you assume. You need to read the docs so that you
    don't have to assume, but can act with knowledge.

    > I think it's a design flaw to close the socket if other steams are still
    > associated with that socket.


    Apparently the API designers thought otherwise.

    --
    Lew
     
    Lew, Jul 4, 2009
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jm
    Replies:
    0
    Views:
    371
  2. Brett Everton
    Replies:
    2
    Views:
    3,408
    Brett Everton
    Jun 4, 2004
  3. Replies:
    5
    Views:
    478
  4. Replies:
    4
    Views:
    2,656
    Oliver Wong
    Sep 29, 2005
  5. Iñaki Baz Castillo
    Replies:
    7
    Views:
    937
    Iñaki Baz Castillo
    Jan 12, 2010
Loading...

Share This Page