Hi All

It seems like the FileChannel.transferFrom(ReadableByteChannel src, long position, long count) method does not throw the documented / expected IOExceptions when a remote party closes its side of a connection. The method instead keeps returning that 0 bytes was read, while internally it sees a -1 on an attempted read, which it hides at the Java source code level.

This causes our LengthDelimitedDecoder to fail to detect such truncated message bodies / connection close events. Interestingly, the channel.isOpen() always returns true, even when tcpdump and netstat shows that the remote end of the connection had closed.

I am attaching a small test class which demonstrates this.. I do not believe it would be possible to change the behavior of the JDK - can we work around this?

regards
asankha

import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class MyTest {
    public static void main(String[] args) throws Exception {
        final ServerSocket ss = new ServerSocket(9000);
        new Thread(new Runnable() {
            public void run() {
                try {
                    Socket s = ss.accept();
PrintWriter out = new PrintWriter(s.getOutputStream(), true);

                    for (int i=0; i<3; i++) {
                        out.println("Hello World " + i);
                        Thread.sleep(1000);
                    }
                    s.close();
                    System.out.println("=> CLOSED socket");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(InetAddress.getLocalHost(), 9000));
        Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

final FileChannel fileChannel = new RandomAccessFile("/tmp/x", "rw").getChannel();
        long pos = 0;
        long count = 0;

        while (selector.select() > 0) {
            Set keys = selector.selectedKeys();
            Iterator it = keys.iterator();

            while (it.hasNext()) {

                SelectionKey key = (SelectionKey) it.next();
                SocketChannel myChannel = (SocketChannel) key.channel();
                it.remove();

                if (key.isConnectable()) {
                    if (myChannel.isConnectionPending()) {
                        myChannel.finishConnect();
                    }
                } else if (key.isReadable()) {
                    count = fileChannel.transferFrom(myChannel, pos, 100);
System.out.println("Transferred : " + count + " socket open ? : " + myChannel.isOpen() + " connected ? : " + myChannel.isConnected());
                    pos += count;
                    Thread.sleep(1000);

                    if (count == 0) {
                        try {

                            int i = myChannel.read(ByteBuffer.allocate(1));
                            System.out.println("read : " + i);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

--
Asankha C. Perera
AdroitLogic, http://adroitlogic.org

http://esbmagic.blogspot.com




---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to