Name: nt126004 Date: 02/26/2002
FULL PRODUCT VERSION :
java version "1.4.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-rc-b91)
Java HotSpot(TM) Client VM (build 1.4.0-rc-b91, mixed mode)
FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]
Service Pack #2
A DESCRIPTION OF THE PROBLEM :
There's a problem when a BufferedOutputStream is used to
wrap the OutputStream returned from a Socket. When I
say "wrap the OutputStream", of course, I mean something
like this:
BufferedOutputStream bos = new BufferedOutputStream
(socket.getOutputStream());
The problem is that the BufferedOutputStream is not always
flushed correctly. There are two cases I've found when this
problem occurs:
1. If the InputStream returned from the Socket is closed
before the BufferedOutputStream, the BufferedOutputStream
is not flushed properly.
2. If the Socket itself is closed before the
BufferedOutputStream, the BufferedOutputStream is not
flushed properly.
I've included a sample program that illustrates case #1,
above. The sample program writes 1,000 bytes to the
BufferedOutputStream but not all of them are received by
the client.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Set up a ServerSocket.
2. Retrieve a Socket from the ServerSocket.
3. Wrap the Socket's OutputStream with a
BufferedOutputStream.
4. Write a few thousand bytes to the BufferedOutputStream.
5. Close the Socket's InputStream (or close the Socket
itself).
6. Close the BufferedOutputStream.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected
--------
I would expect all the bytes written to the
BufferedOutputStream to be sent to the client, regardless
of whether the BufferedOutputStream is closed before or
after the InputStream or the Socket.
The order of stream closing should *not* affect whether or
not the BufferedOutputStream is properly fushed. I *SHOULD*
be able to either close the InputStream *OR* close the
Socket itself and know that the BufferedOutputStream will
be properly fushed.
Actual
------
If the InputStream returned from the Socket is closed
before the BufferedOutputStream (which wraps the
OutputStream returned from the Socket), then the
BufferedOutputStream is not properly flushed.
If the Socket itself is closed before the
BufferedOutputStream (which wraps the OutputStream returned
from the Socket), then the BufferedOutputStream is not
properly flushed.
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.net.*;
class Tester {
public static void main(String[] args) throws Exception {
// Set up the server
new Thread() {
public void run() {
ServerSocket ss = null;
Socket s = null;
OutputStream bos = null;
InputStream is = null;
try {
ss = new ServerSocket(4444);
s = ss.accept();
// Get the InputStream and OutputStream from the Socket.
is = s.getInputStream();
bos = new BufferedOutputStream(s.getOutputStream());
int BYTES_TO_GENERATE = 1000;
// Write the bytes....
for(int i = 0; i < BYTES_TO_GENERATE; ++i)
bos.write(i);
} catch(Exception e) {
System.err.println("There was an exception in the server code: " + e);
e.printStackTrace();
} finally {
try {
// Close the server socket.
ss.close();
// The BufferedOutputStream is not properly flushed in these two
// situations:
//
// 1. Closing the InputStream before the BuffereredOutputStream.
// 2. Closing the Socket before the BufferedOutputStream.
//
// If we close the BufferedOutputStream before
// closing the InputStream or clsoing the Socket *OR* we simply
// use an OutputStream rather than a BufferedOutputStream, this
// problem goes away.
is.close(); //close InputStream, comment this for correct behavior
bos.close(); //close the BufferedOutputStream
s.close(); //close the Socket
} catch(Exception e) {
System.err.println("Exception closing something..." + e);
}
}
} // run()
}.start(); // start the server thread
// 10KB Buffer to read in the data from the server.
byte[] b = new byte[10 * 1024];
// Open a connection to the server
Socket s = new Socket("localhost", 4444);
InputStream is = s.getInputStream();
int bytesReadSoFar = 0;
int bytesRead = 0;
while((bytesRead = is.read(b)) != -1)
bytesReadSoFar += bytesRead;
System.out.println("The client read a total of " + bytesReadSoFar + "
bytes.");
is.close();
s.close();
} // main()
} // Tester
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
If using a BufferedOutputStream to wrap the OutputStream
returned from the Socket, be sure to close the
BufferedOutputStream *BEFORE* closing either the
InputStream returned from the Socket or the Socket itself.
(Review ID: 139479)
======================================================================