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

D

Duane Evenson

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");
}
}
 
D

Duane Evenson

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.
 
L

Lew

Duane 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.

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?
 
R

Roedy Green

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.
 
M

markspace

Roedy said:
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.
 
M

markspace

Duane 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.

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);
}
}

}
 
R

Roedy Green

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.
 
L

Lew

markspace 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.

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.
 
M

markspace

Lew said:
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.
 
D

Duane Evenson

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.
 
L

Lew

Duane said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top