Thinking in Enterprise Java 里的例子
//: TIEJ:X1:NonBlockingIO.java
// Socket and selector configuration for non-blocking
// Connects to JabberServer.java
// {RunByHand}
import java.net.*;
import java.nio.channels.*;
import java.util.*;
import java.io.*;
/**
* Aim: Shows how to use selector. No reading/writing
* just shows the readiness of operations.
*
* PseudoCode:
* -> Create a selector.
* -> Create a channel
* -> Bind the socket associated with this channel to a
* <client-port>
* -> Configure the channel as non-blocking
* -> Register the channel with selector.
* -> Invoke select() so that it blocks until registered
* channel is ready. (as opposed to select(long timeout)
* -> Get the set of keys whose underlying channel is ready
* for the operation they showed interest when they
* registered with the selector.
* -> Iterate through the keys.
* -> For every key check if the underlying channel is ready
* for the operation it is interested in.
* -> If ready print message of readiness.
*
* Notes:
* -> Need MultiJabberServer running on the local machine.
* You run it to connect to the local MultiJabberServer
* -> It causes and exception at MultiJabberServer but
* this exception is expected.
*/
public class NonBlockingIO {
public static void main(String[] args)
throws IOException {
if(args.length < 2) {
System.out.println(
"Usage: java <client port> <local server port>");
System.exit(1);
}
int cPort = Integer.parseInt(args[0]);
int sPort = Integer.parseInt(args[1]);
SocketChannel ch = SocketChannel.open();
Selector sel = sel = Selector.open();
try {
ch.socket().bind(new InetSocketAddress(cPort));
ch.configureBlocking(false);
// channel interested in performing read/write/connect
ch.register(sel, SelectionKey.OP_READ
| SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT);
// Unblocks when ready to read/write/connect
sel.select();
// Keys whose underlying channel is ready, the
// operation this channel is interested in can be
// performed without blocking.
Iterator it = sel.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = (SelectionKey)it.next();
it.remove();
// Is underlying channel of key ready to connect?
// if((key.readyOps() & SelectionKey.OP_CONNECT) != 0) {
if(key.isConnectable()) {
InetAddress ad = InetAddress.getLocalHost();
System.out.println("Connect will not block");
//You must check the return value of connect to make
//sure that it has connected. This call being
//non-blocking may return without connecting when
//there is no server where you are trying to connect
//Hence you call finishConnect() that finishes the
//connect operation.
if(!ch.connect(new InetSocketAddress(ad, sPort)))
ch.finishConnect();
}
// Is underlying channel of key ready to read?
// if((key.readyOps() & SelectionKey.OP_READ) != 0)
if(key.isReadable())
System.out.println("Read will not block");
// Is underlying channel of key ready to write?
// if((key.readyOps() & SelectionKey.OP_WRITE) != 0)
if(key.isWritable())
System.out.println("Write will not block");
}
} finally {
ch.close();
sel.close();
}
}
} ///:~
//: TIEJ:X1:JabberClient1.java
// Very simple client that just sends lines to the server
// and reads lines that the server sends.
// {RunByHand}
import java.net.*;
import java.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class JabberClient1 {
public static void main(String[] args)
throws IOException {
if(args.length < 1) {
System.out.println(
"Usage: java JabberClient1 <client-port>");
System.exit(1);
}
int clPrt = Integer.parseInt(args[0]);
SocketChannel sc = SocketChannel.open();
Selector sel = Selector.open();
try {
sc.configureBlocking(false);
sc.socket().bind(new InetSocketAddress(clPrt));
sc.register(sel, SelectionKey.OP_READ |
SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT);
int i = 0;
// Because of the asynchronous nature you do not know
// when reading and writing is done, hence you need to
// keep track of this, boolean written is used to
// alternate between read and write. Whatever is written
// is echoed and should be read.
// boolean done is used to check when to break out of
// the loop
boolean written = false, done = false;
//JabberServer.java to which this client connects writes
//using BufferedWriter.println(). This method performs
//encoding according to the defualt charset
String encoding = System.getProperty("file.encoding");
Charset cs = Charset.forName(encoding);
ByteBuffer buf = ByteBuffer.allocate(16);
while(!done) {
sel.select();
Iterator it = sel.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = (SelectionKey)it.next();
it.remove();
sc = (SocketChannel)key.channel();
if(key.isConnectable() && !sc.isConnected()) {
InetAddress addr = InetAddress.getByName(null);
boolean success = sc.connect(
new InetSocketAddress(addr,
JabberServer.PORT));
if(!success) sc.finishConnect();
}
if(key.isReadable() && written) {
if(sc.read((ByteBuffer)buf.clear()) > 0) {
written = false;
String response = cs.decode(
(ByteBuffer) buf.flip()).toString();
System.out.print(response);
if(response.indexOf("END") != -1) done = true;
}
}
if(key.isWritable() && !written) {
if(i < 10) sc.write(ByteBuffer.wrap(
new String("howdy "+ i + '\n').getBytes()));
else if(i == 10) sc.write(ByteBuffer.wrap(
new String("END\n").getBytes()));
written = true;
i++;
}
}
}
} finally {
sc.close();
sel.close();
}
}
} ///:~
//: TIEJ:X1:MultiJabberServer1.java
// Has the same semantics as multi-threaded
// MultiJabberServer
// {RunByHand}
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.util.*;
/**
* The Server accepts connections in non-blocking fashion.
* A connection when established, a socket is created,
* which is registered for read/write with the selector.
* Reading/Writing is performed on this socket when the
* selector unblocks.
* This program works exactly the same way as MultiJabberServer.
*/
public class MultiJabberServer1 {
public static final int PORT = 8080;
public static void main(String[] args)
throws IOException {
//Channel read from data will be in ByteBuffer form
//written by PrintWriter.println(). Decoding of this
//byte stream requires character set of default encoding.
String encoding = System.getProperty("file.encoding");
//Had to initialized here since we do not wish to create
//a new instance of Charset everytime it is required
//Charset cs = Charset.forName(
// System.getProperty("file.encoding"));
Charset cs = Charset.forName(encoding);
ByteBuffer buffer = ByteBuffer.allocate(16);
SocketChannel ch = null;
ServerSocketChannel ssc = ServerSocketChannel.open();
Selector sel = Selector.open();
try {
ssc.configureBlocking(false);
//Local address on which it will listen for connections
//Note: Socket.getChannel() returns null unless a channel
//is associated with it as shown below.
//i.e the expression (ssc.socket().getChannel() != null) is true
ssc.socket().bind(new InetSocketAddress(PORT));
// Channel is interested in OP_ACCEPT events
SelectionKey key =
ssc.register(sel, SelectionKey.OP_ACCEPT);
System.out.println("Server on port: " + PORT);
while(true) {
sel.select();
Iterator it = sel.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey skey = (SelectionKey)it.next();
it.remove();
if(skey.isAcceptable()) {
ch = ssc.accept();
System.out.println(
"Accepted connection from:" + ch.socket());
ch.configureBlocking(false);
ch.register(sel, SelectionKey.OP_READ);
} else {
// Note no check performed if the channel
// is writable or readable - to keep it simple
ch = (SocketChannel)skey.channel();
ch.read(buffer);
CharBuffer cb = cs.decode(
(ByteBuffer)buffer.flip());
String response = cb.toString();
System.out.print("Echoing : " + response);
ch.write((ByteBuffer)buffer.rewind());
if(response.indexOf("END") != -1) ch.close();
buffer.clear();
}
}
}
} finally {
if(ch != null) ch.close();
ssc.close();
sel.close();
}
}
} ///:~