见下面代码的:Thread.sleep(400000)部分,这里暂停线程模拟耗时操作后,别的客户端就连接不上了
[code="java"]
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* @author marlonyao<yaolei135@gmail.com>
*
*/
public class EchoServer3 {
public static int DEFAULT_PORT = 9898;
interface Handler {
void execute(Selector selector, SelectionKey key);
}
public static void main(String[] args) throws IOException {
System.out.println("Listening for connection on port " + DEFAULT_PORT);
Selector selector = Selector.open();
initServer(selector);
while (true) {
selector.select();
for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor.hasNext();) {
SelectionKey key = (SelectionKey) itor.next();
itor.remove();
Handler handler = (Handler) key.attachment();
handler.execute(selector, key);
}
}
}
private static void initServer(Selector selector) throws IOException,
ClosedChannelException {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
ServerSocket ss = serverChannel.socket();
ss.bind(new InetSocketAddress(DEFAULT_PORT));
serverChannel.configureBlocking(false);
SelectionKey serverKey = serverChannel.register(selector, SelectionKey.OP_ACCEPT);
serverKey.attach(new ServerHandler());
}
static class ServerHandler implements Handler {
public void execute(Selector selector, SelectionKey key) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = null;
try {
client = server.accept();
System.out.println("Accepted connection from " + client);
} catch (IOException e) {
e.printStackTrace();
return;
}
SelectionKey clientKey = null;
try {
client.configureBlocking(false);
clientKey = client.register(selector, SelectionKey.OP_READ);
clientKey.attach(new ClientHandler());
} catch (IOException e) {
if (clientKey != null)
clientKey.cancel();
try { client.close(); } catch (IOException ioe) { }
}
}
}
static class ClientHandler implements Handler {
private ByteBuffer buffer;
public ClientHandler() {
buffer = ByteBuffer.allocate(100);
}
public void execute(Selector selector, SelectionKey key) {
try {
if (key.isReadable()) {
readKey(selector, key);
} else if (key.isWritable()) {
writeKey(selector, key);
}
} catch (IOException e) {
key.cancel();
try { key.channel().close(); } catch (IOException ioe) { }
}
}
private void readKey(Selector selector, SelectionKey key) throws IOException {
SocketChannel client = (SocketChannel) key.channel();
try {
Thread.sleep(400000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int n = client.read(buffer);
if (n > 0) {
buffer.flip();
key.interestOps(SelectionKey.OP_WRITE); // switch to OP_WRITE
}
}
private void writeKey(Selector selector, SelectionKey key) throws IOException {
System.out.println("is writable...");
SocketChannel client = (SocketChannel) key.channel();
client.write(buffer);
if (buffer.remaining() == 0) { // write finished, switch to OP_READ
buffer.clear();
key.interestOps(SelectionKey.OP_READ);
}
}
}
}
[/code]
获取连接,分发处理,获取key这个是主线程,但是后续处理应该另起线程,handler应该是新起的线程处理,例如这样:
[code="java"]
while (true)
{
selector.select();
Set keys = selector.selectedKeys();
for (SelectionKey key : keys)
{
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT)
{
ServerSocketChannel ss = (ServerSocketChannel) key
.channel();
SocketChannel sc = ss.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
keys.remove(key);
}
if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ)
{
SocketChannel cc = (SocketChannel) key.channel();
if (ReadThread.tag)
{
ReadThread readThread = new ReadThread();
readThread.setChannel(cc);
readThread.start();
keys.remove(key);
ReadThread.tag = false;
}
}
}
}
[/code]
好比去肯德基吃饭,前台只有一个点餐员,如果客人要的餐简单,能快速的完成点餐(相当于IO处理),然后让客人等厨师做好饭(相当于后台业务处理),然后通知客人取餐。 这个时候能快速接受排队的客人的请求。 如果某个客人要了很多吃的,点餐的时间就比较长,后面排队的客人就要等,这时效率就低了