package com.ronsoft.books.nio.channels; import java.nio.ByteBuffer; import java.nio.channels.InterruptibleChannel; import java.nio.channels.FileChannel; import java.nio.channels.ByteChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.io.FileInputStream; import java.net.InetSocketAddress; import java.text.SimpleDateFormat; import java.util.Date; /** * Test interrupt and async close semantics of InterruptibleChannel objects. * This is test code to demonstrate bugs in the 1.4.0 implementation. * Use of /dev/tty with FileChannel will probably not work in future releases. * * @author Ron Hitchens (ron@ronsoft.com) * $Id: ChannelClose.java,v 1.3 2002/05/20 07:24:29 ron Exp $ */ public class ChannelClose { // Include a port number command line arg to use sockets, otherwise // /dev/tty will be used. If you use sockets, use telnet in another // window to connect to the port and type some input. public static void main (String [] argv) throws Exception { int port = 0; if (argv.length > 0) { port = Integer.parseInt (argv [0]); } Thread.currentThread().setName ("Main"); System.out.println ("--- Testing Interrupt Thread ---"); testInterrupt (newChannel (port)); System.out.println (""); System.out.println ("--- Testing Async Channel Close ---"); testAsyncClose (newChannel (port)); } // Create a new channel: if port == 0, FileChannel on /dev/tty, else // a SocketChannel from the first accept on the given port number private static ByteChannel newChannel (int netPort) throws Exception { if (netPort == 0) { FileInputStream fis = new FileInputStream ("/dev/tty"); return (fis.getChannel()); } else { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind (new InetSocketAddress (netPort)); System.out.print ("Waiting for connection on port " + netPort + "..."); System.out.flush(); ByteChannel channel = ssc.accept(); ssc.close(); System.out.println ("Got it"); return (channel); } } private static void testInterrupt (ByteChannel channel) throws Exception { Sleeper sleeper = new Sleeper (channel); sleeper.setName ("Sleeper"); try { ByteBuffer buffer = ByteBuffer.allocate (100); println ("starting sleeper thread"); sleeper.start(); println ("waiting for sleeper thread to issue read..."); Thread.sleep (1000); println ("interrupting sleeper"); sleeper.interrupt(); Thread.sleep (100); // avoid race with sleeper println ("issuing read on interrupted channel..."); channel.read (buffer); println ("read completed OK"); } catch (Throwable e) { println ("Caught " + e); } finally { println ("closing channel"); channel.close(); println ("joining sleeper " + "(you may need to type something)..."); sleeper.join(); } } private static void testAsyncClose (ByteChannel channel) throws Exception { Sleeper sleeper = new Sleeper (channel); sleeper.setName ("Sleeper"); try { ByteBuffer buffer = ByteBuffer.allocate (100); println ("starting sleeper thread"); sleeper.start(); println ("waiting for sleeper thread to issue read..."); Thread.sleep (1000); println ("closing channel"); channel.close(); println ("joining sleeper " + "(you may need to type something)..."); sleeper.join(); } catch (Throwable e) { println ("Caught " + e); } } // print output with a timestamp and the thread name. private static void println (String s) { SimpleDateFormat df = new SimpleDateFormat ( "HH:mm:ss.SSS"); String ds = df.format (new Date()); System.out.println (ds + " (" + Thread.currentThread().getName() + "): " + s); } // -------------------------------------------------------- private static class Sleeper extends Thread { private ByteChannel channel; public Sleeper (ByteChannel channel) { super(); this.channel = channel; } public void run() { ByteBuffer buffer = ByteBuffer.allocate (100); try { println ("issuing read..."); int n = this.channel.read (buffer); println ("read complete, " + "bytes read=" + n); System.out.print (" Buffer: '"); buffer.flip(); while (buffer.hasRemaining()) { char c = (char) buffer.get(); switch (c) { case '\n': System.out.print ("\\n"); break; case '\r': System.out.print ("\\r"); break; default: System.out.print (c); break; } } System.out.println ("'"); } catch (Throwable e) { println ("caught " + e); } finally { println ("exiting, " + "interrupted=" + isInterrupted()); } } } }