package NIO;import java.io.IOException;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.Socket;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.nio.channels.spi.SelectorProvider;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.Map;import java.util.Set;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class NIOServer {private Selector selector;private ExecutorService tp = Executors.newCachedThreadPool();public static Map<Socket, Long> time_start = new HashMap<Socket, Long>(1024);public static void main(String[] args) {}private void startServer() throws Exception {// 工厂方法获取selectorselector = SelectorProvider.provider().openSelector();// 服务器端SocketChannel实例ServerSocketChannel ssc = ServerSocketChannel.open();// 设置为非阻塞模式ssc.configureBlocking(false);InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), 8000);// InetSocketAddress isa = new InetSocketAddress(8000);// 将套接字绑定到本地地址ssc.socket().bind(isa);// 将SocketChannel绑定到Seletorssc.register(selector, SelectionKey.OP_ACCEPT);// 等待分发网络消息for (;;) {// 阻塞方法,若数据没有等待好则等待,否则就返回SelectionKey的数量selector.select();// 获取准备好的SelectionKeySet readKeys = selector.selectedKeys();Iterator iterator = readKeys.iterator();long e = 0;while (iterator.hasNext()) {SelectionKey sk = (SelectionKey) iterator.next();// 处理完后移除SelectionKey,防止重复处理iterator.remove();if (sk.isAcceptable()) {doAccpet(sk);} else if (sk.isValid() && sk.isReadable()) {if (!time_start.containsKey(((SocketChannel) sk.channel()).socket())) {time_start.put(((SocketChannel) sk.channel()).socket(), System.currentTimeMillis());}doRead(sk);} else if (sk.isValid() && sk.isWritable()) {doWrite(sk);e = System.currentTimeMillis();long b = time_start.remove(((SocketChannel) sk.channel()).socket());System.out.println("spend:" + (e - b) + "ms");}}}}private void doWrite(SelectionKey sk) {SocketChannel channel = (SocketChannel) sk.channel();EchoClient echoClient = (EchoClient) sk.attachment();LinkedList<ByteBuffer> ouqt = echoClient.getOutputQueue();ByteBuffer bb = ouqt.getLast();try {int len = channel.write(bb);if (len == -1) {disconnect(sk);return;}// 写入完成,移除,remaining返回当前位置与限制之间的元素数if (bb.remaining() == 0) {ouqt.removeLast();}} catch (IOException e) {System.out.println("Failed to write to client");e.printStackTrace();disconnect(sk);}if (ouqt.size() == 0) {sk.interestOps(SelectionKey.OP_READ);}}private void doRead(SelectionKey sk) {SocketChannel channel = (SocketChannel) sk.channel();ByteBuffer bb = ByteBuffer.allocate(8192);int len;try {len = channel.read(bb);if (len < 0) {disconnect(sk);return;}} catch (IOException e) {System.out.println("failed to read from client");e.printStackTrace();disconnect(sk);return;}// 反转此缓冲区bb.flip();tp.execute(new HandlerMsg(sk, bb));}private void disconnect(SelectionKey sk) {if (sk != null) {sk.cancel();sk = null;}}/*** @param sk* 进行客户端接受*/private void doAccpet(SelectionKey sk) {ServerSocketChannel server = (ServerSocketChannel) sk.channel();SocketChannel clientChannel;try {// 客户端通信通道clientChannel = server.accept();clientChannel.configureBlocking(false);SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ);EchoClient echoClient = new EchoClient();clientKey.attach(echoClient);InetAddress clientAddress = clientChannel.socket().getInetAddress();System.out.println("Accept connection form " + clientAddress.getHostAddress() + ".");} catch (IOException e) {System.out.println("Failed to accept new client.");e.printStackTrace();}}class HandlerMsg implements Runnable {SelectionKey sk;ByteBuffer bb;public HandlerMsg(SelectionKey sk, ByteBuffer bb) {this.sk = sk;this.bb = bb;}@Overridepublic void run() {EchoClient echoClient = (EchoClient) sk.attachment();echoClient.enqueue(bb);sk.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);// 强迫selector立即返回selector.wakeup();}}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。