001
002 import java.util.Set;
003
004 import java.io.IOException;
005 import java.net.BindException;
006 import java.net.InetSocketAddress;
007 import java.net.Socket;
008 import java.net.ServerSocket;
009
010 import java.nio.channels.Selector;
011 import java.nio.channels.SelectionKey;
012 import java.nio.channels.ServerSocketChannel;
013 //import java.nio.channels.SocketChannel;
014
015
016 /**
017 * ChannelFactoryNio.
018 * Socket channel factory using java.nio and no Thread.
019 *
020 * Usage: ChannelFactoryNio(port).
021 * @author Heinz Kredel.
022 */
023 public class ChannelFactoryNio extends Thread {
024
025 /**
026 * default port of socket.
027 */
028 public final static int DEFAULT_PORT = 4711;
029
030 /**
031 * wait time 500ms.
032 */
033 public final static int WAIT_TIME = 500;
034
035 /**
036 * port of socket.
037 */
038 private final int port;
039
040 /**
041 * local selector.
042 */
043 private Selector selector = null;
044
045 /**
046 * local server key.
047 */
048 private SelectionKey serverkey = null;
049
050 /**
051 * local server socket channel.
052 */
053 private ServerSocketChannel server = null;
054
055
056 /**
057 * Constructs a ChannelFactory using Nio.
058 * @param p port.
059 */
060 public ChannelFactoryNio(int p) {
061 if ( p <= 0 ) {
062 port = DEFAULT_PORT;
063 } else {
064 port = p;
065 }
066 try {
067 selector = Selector.open();
068
069 server = ServerSocketChannel.open();
070 server.configureBlocking(false);
071 serverkey = server.register(selector,SelectionKey.OP_ACCEPT);
072 server.socket().bind( new InetSocketAddress(port) );
073
074 System.out.println("server started on port "+port);
075 } catch (BindException e) {
076 System.out.println(e);
077 serverkey.cancel();
078 //server.close();
079 } catch (IOException e) {
080 e.printStackTrace();
081 }
082 }
083
084
085 /**
086 * Constructs a ChannelFactory Nio.
087 * on the DEFAULT_PORT.
088 */
089 public ChannelFactoryNio() {
090 this(DEFAULT_PORT);
091 }
092
093
094 /**
095 * Get a new socket channel from a server socket.
096 */
097 public SocketChannel getChannel()
098 throws IOException {
099 SocketChannel c = null;
100 java.nio.channels.SocketChannel s;
101 while (c == null) {
102 try {
103 System.out.println("waiting for connection");
104 selector.select(); // blocking
105
106 Set<SelectionKey> keys = selector.selectedKeys();
107 for ( SelectionKey k: keys ) {
108 if ( k == serverkey ) {
109 if ( k.isAcceptable() ) { // just in case
110 keys.remove(k);
111 s = server.accept();
112 s.configureBlocking(true);
113 c = new SocketChannel( s.socket() );
114 System.out.println("connection accepted");
115 break; // ignore other keys
116 }
117 } else { // ignore client keys
118 selector.wakeup();
119 }
120 }
121 } catch (IOException e) {
122 System.out.println(e);
123 try { // wait for next client to connect
124 Thread.currentThread().sleep( WAIT_TIME );
125 } catch (InterruptedException ignored) { }
126 }
127 }
128 return c;
129 }
130
131
132 /**
133 * Get a new socket channel to a given host.
134 * @param h hostname.
135 * @param p port.
136 */
137 public SocketChannel getChannel(String h, int p)
138 throws IOException {
139 if ( p <= 0 ) {
140 p = port;
141 }
142 SelectionKey clientkey = null;
143 SocketChannel c = null;
144 java.nio.channels.SocketChannel client;
145 System.out.println("connecting to "+h);
146 while (c == null) {
147 try {
148 client = java.nio.channels.SocketChannel.open();
149 client.configureBlocking(false);
150 clientkey = client.register(selector,SelectionKey.OP_CONNECT);
151 client.connect( new InetSocketAddress(h,p) );
152
153 selector.select(); // blocking
154
155 Set<SelectionKey> keys = selector.selectedKeys();
156 for ( SelectionKey k: keys ) {
157 if ( k == clientkey ) {
158 if ( k.isConnectable() ) { // if server ready
159 keys.remove(k);
160 k.cancel(); // required to make blockable
161 client = (java.nio.channels.SocketChannel) k.channel();
162 client.finishConnect();
163 client.configureBlocking(true);
164 c = new SocketChannel( client.socket() );
165 break; // ignore other keys
166 }
167 } else { // ignore server keys
168 selector.wakeup();
169 }
170 }
171 } catch (IOException e) {
172 System.out.println(e);
173 System.out.println("Server on "+h+" not ready");
174 try { // wait server ready
175 Thread.currentThread().sleep( WAIT_TIME );
176 } catch (InterruptedException ignored) { }
177 }
178 }
179 System.out.println("connected");
180 return c;
181 }
182
183
184 /**
185 * Close the Channel Factory.
186 */
187 public void close() {
188 try {
189 serverkey.cancel();
190 selector.close();
191 server.close();
192 } catch (IOException e) {
193 e.printStackTrace();
194 }
195 }
196
197 }
198