NIO进行服务端开发的一般步骤:
创建一个ServerSocketChannel,并配置它为非阻塞模式;绑定监听,配置相关的TCP参数,比如backlog大小;创建一个独立的I/O进程,用于轮询多路复用器Selector创建Selector,将之前创建的ServerSocketChannel注册到Selector上,监听SelectionKey.ACCEPT事件启动I/O线程,在一个循环体中执行Selecttor.selector()方法,轮询就绪的Channel当轮询到就绪的Channel的时候,就需要对它的状态进行判断,如果是OP_ACCEPT状态,说明在这个时候,有客户端接入了,需要调用ServerSocketChannel.accept()方法接收新的客户端;设置新接入的客户端链路SocketChannel为非阻塞模式,并配置一些TCP参数将SocketChannel注册到Selector,监听OP_READ事件如果轮询到了OP_READ事件,则说明在SocketChannel中有新的就绪数据包,这时候需要创建ByteBuffer读取数据包;如果轮询到channel中的事件为OP_WRITE,说明还有数据包没有发送完成,需要继续进行发送下面以一个简单的Demo来说明NIO的使用方法:
package study170301;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.Iterator;import java.util.Set;public class NioServer { public void run() { new Thread(new MultipexerTimeServer(8080)).start(); // 启动服务器 } public static void main(String[] args) { new NioServer().run(); } class MultipexerTimeServer implements Runnable { PRivate Selector selector; private ServerSocketChannel serverChannel; private volatile boolean stop; public MultipexerTimeServer(int port) { try { serverChannel = ServerSocketChannel.open(); selector = Selector.open(); serverChannel.configureBlocking(false); serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 注册连接事件 serverChannel.socket().bind(new InetSocketAddress(port), 1024); System.out.printf("Server is started in %s:/n", port); } catch (IOException e) { e.printStackTrace(); } } public void stop() { this.stop = true; } private void handleEvent(SelectionKey key) { // 只有在key合法的情况下,才对相应的事件做处理 if (key.isValid()) { // 处理客户端的连接事件 if (key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); try { SocketChannel sc = ssc.accept(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_READ); // 注册可读事件 } catch (IOException e) { e.printStackTrace(); } } // 处理读事件 if (key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); // 创建一个1024的空间 try { int bytes = socketChannel.read(readBuffer); if (bytes > 0) { readBuffer.flip(); // 从缓存中出数据 byte[] bt = new byte[readBuffer.remaining()]; // 创建一个byte,用来装数据 readBuffer.get(bt); System.out.println(new String(bt)); // 输出从客户端读到的数据 } } catch (IOException e) { e.printStackTrace(); } } } else { System.out.println("key is not valid..."); } } @Override public void run() { while (!stop) { try { selector.select(1000); Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); SelectionKey key = null; while (it.hasNext()) { key = it.next(); it.remove(); // 在这里对key进行处理 handleEvent(key); } } catch (IOException e) { e.printStackTrace(); } // 设置轮询扫描的时间间隔 } } }}新闻热点
疑难解答