问题描述
见下面代码的:Thread.sleep(400000)部分,这里暂停线程模拟耗时操作后,别的客户端就连接不上了 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); } } } } 问题补充:wangqj 写道
解决方案
获取连接,分发处理,获取key这个是主线程,但是后续处理应该另起线程,handler应该是新起的线程处理,例如这样: while (true) { selector.select(); Set<SelectionKey> 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; } } } }
解决方案二:
好比去肯德基吃饭,前台只有一个点餐员,如果客人要的餐简单,能快速的完成点餐(相当于IO处理),然后让客人等厨师做好饭(相当于后台业务处理),然后通知客人取餐。 这个时候能快速接受排队的客人的请求。 如果某个客人要了很多吃的,点餐的时间就比较长,后面排队的客人就要等,这时效率就低了