Name: nt126004 Date: 06/04/2002
FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)
FULL OPERATING SYSTEM VERSION :
Windows 2000 SP 2
A DESCRIPTION OF THE PROBLEM :
The new nio SocketChannel API writes don't seem to flush
correctly to old JDK 1.3 Sockets. We have an existing
client application that connects to a server that's being
rearchitected to use nio non-blocking sockets. The JDK 1.3
client hangs on reads from the server. We've verified that
all writes are being sent through the socket channel.
I've written a quickie test case.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run nio_server in a 1.4 java VM on Windows 2000.
2. Run blocking_client in a 1.3 java VM on Windows 2000.
EXPECTED VERSUS ACTUAL BEHAVIOR :
The client should print "n. Waiting." and then a
corresponding "n. Done." forever. Early on in the run, the
Waits will get hung. However, when I use old-style server
code, it never hangs. Further, if I use a new-style nio
client, it never hangs.
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
Here's a canned JDK 1.4 server. Run under JDK 1.4:
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.io.*;
import java.util.*;
public class nio_server
{
public static void main(String[] args) throws Exception
{
Selector selector = Selector.open
();
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
InetSocketAddress address = new InetSocketAddress(10064);
server.socket().bind(address);
server.register(selector, SelectionKey.OP_ACCEPT);
for(;;)
{
if ( selector.select() > 0 )
{
Iterator iterator = selector.selectedKeys().iterator();
while ( iterator.hasNext() )
{
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if ( key.isAcceptable() )
{
SocketChannel socket = server.accept();
socket.configureBlocking(false);
SelectionKey
socket_key = socket.register(selector, SelectionKey.OP_READ |
SelectionKey.OP_WRITE);
socket_holder holder = new socket_holder(socket);
socket_key.attach(holder);
}
else if ( key.isReadable() )
{
socket_holder holder = (socket_holder)
key.attachment();
holder.do_read();
}
}
}
}
}
private static class socket_holder
{
public socket_holder(SocketChannel socket)
{
socket_mbr = socket;
}
public void do_read() throws IOException
{
ByteBuffer buffer = ByteBuffer.allocate(1024);
read_loop: for(;;)
{
buffer.clear();
socket_mbr.read(buffer);
buffer.flip();
for ( int i = 0; i < buffer.limit(); ++i )
{
if ( (char)(buffer.get(i) & 0xff)
== '\n' )
{
break read_loop;
}
}
}
buffer = ByteBuffer.allocate(32767);
for ( int i = 0; i < buffer.capacity() - 1; ++i )
{
buffer.put((byte)('a' & 0xff));
}
buffer.put((byte)('x' & 0xff));
buffer.rewind();
while ( buffer.hasRemaining() )
{
socket_mbr.write(buffer);
}
}
private SocketChannel socket_mbr;
}
}
Here's a JDK 1.3 client. Run under JDK 1.3:
import java.net.*;
import java.io.*;
import java.util.*;
public class blocking_client
{
public static void main(String[] args) throws Exception
{
for ( int i = 0; i < 10; ++i )
{
final int index = i;
Thread a_thread = new Thread()
{
public void run()
{
Random
r = new Random(System.currentTimeMillis());
for(;;)
{
try
{
Thread.sleep(r.nextInt
(500));
}
catch ( InterruptedException e )
{
}
try
{
do_it(index);
}
catch ( IOException e )
{
e.printStackTrace();
}
}
}
};
a_thread.start();
}
}
private static void do_it(int index) throws IOException
{
Socket s = new Socket
("localhost", 10064);
PrintStream out = new PrintStream
(new BufferedOutputStream(s.getOutputStream()));
InputStream in = new
BufferedInputStream(s.getInputStream());
out.print("x\r\n");
out.flush();
System.out.println(index + ". Waiting.");
for(;;)
{
int b = in.read();
char c = (char)(b & 0xff);
if ( c == 'x' )
{
break;
}
}
System.out.println(index + ". Done.");
}
}
---------- END SOURCE ----------
(Review ID: 145803)
======================================================================