package javademo.net; /** * @author Fan Hongtao */ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Date; import java.util.Iterator; public class AsyncServer implements Runnable { private final static int MAX_LENGTH = 64 * 1024; private ByteBuffer readBuffer = ByteBuffer.allocate(MAX_LENGTH); private ByteBuffer writeBuffer = ByteBuffer.allocate(MAX_LENGTH); /** 服务端口 */ private int port = 0; public AsyncServer(int port) { this.port = port; new Thread(this).start(); } public void run() { log("Try to start server with port " + port); try { // 生成一个侦听端 ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); // 将侦听端设为异步方式 Selector selector = Selector.open(); // 生成一个信号监视器 // 侦听端绑定到一个端口 serverChannel.socket().bind(new InetSocketAddress(port)); // 设置侦听端所选的异步信号OP_ACCEPT, 这样才能够新的连接 serverChannel.register(selector, SelectionKey.OP_ACCEPT); log("echo server has been set up ......"); while (true) { if (selector.select(5000) != 0) { log("event occur"); processIOEvent(selector); } else { // 没有指定的I/O事件发生 log("time out....."); } // do something other than sockets processing // for example, local msg-queue or DB } } catch (Exception e) { e.printStackTrace(); } } /** * 处理IO事件 * * @param selector * @throws IOException */ private void processIOEvent(Selector selector) throws IOException { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); if (key.isAcceptable()) { // 侦听端信号触发 ServerSocketChannel server = (ServerSocketChannel) key.channel(); // 接受一个新的连接 SocketChannel client = server.accept(); client.configureBlocking(false); // 设置该socket的异步信号OP_READ // 当socket中有数据时,会触发 processIOEvent // 通过 key.isReadable() 判断,最终调用 receiveDataFromClient() client.register(selector, SelectionKey.OP_READ); log("Accept a client , port is " + client.socket().getPort()); } if (key.isReadable()) { log("Receive date from client"); // 某socket可读信号 receiveDataFromClient(key); } iterator.remove(); } } /** * 处理来自客户端的消息 * * @param key 代表对应的客户端 * */ public void receiveDataFromClient(SelectionKey key) { // 由key获取指定socket channel的引用 SocketChannel clientChannel = (SocketChannel) key.channel(); readBuffer.clear(); try { // 读取数据到readBuffer while (clientChannel.read(readBuffer) > 0) { ; // do nothing } // 确保 readBuffer 可读 readBuffer.flip(); // 将 readBuffer 内容拷入 writeBuffer writeBuffer.clear(); writeBuffer.put(readBuffer); writeBuffer.flip(); // 将数据返回给客户端 while (writeBuffer.hasRemaining()) { clientChannel.write(writeBuffer); } } catch (IOException e) { e.printStackTrace(); log("close a client , port is " + clientChannel.socket().getPort()); key.cancel(); try { key.channel().close(); } catch (IOException e1) { e1.printStackTrace(); } } } /** * 记录日志 * @param logInfo 日志信息 */ @SuppressWarnings("deprecation") private void log(String logInfo) { Date date = new Date(); System.out.println(date.toLocaleString() + ", " + logInfo); } /** * @param args */ public static void main(String[] args) { int port = 3456; if (args.length == 1) { port = Integer.parseInt(args[0]); } new AsyncServer(port); } }