NIO,即none-blocking I/O(非阻塞I/O),和BIO是相对的存在,BIO称为blocking I/O即阻塞I/O。其实我自己理解中的NIO的N并不单单只是none的意思,还有new的意思,就是指NIO是区别于传统阻塞I/O的一种全新的I/O方式。
对于NIO的相关基础知识,我推荐一个系列教程,是国外大佬写的国人翻译的,感觉还不错,可以看看
Java NIO系列教程(一) Java NIO 概述
Java NIO系列教程(二) Channel
Java NIO系列教程(三) Buffer
Java NIO系列教程(四) Scatter/Gather
Java NIO系列教程(五) 通道之间的数据传输
Java NIO系列教程(六) Selector
Java NIO系列教程(七) FileChannel
Java NIO系列教程(八) SocketChannel
Java NIO系列教程(九) ServerSocketChannel
Java NIO系列教程(十) Java NIO DatagramChannel
Java NIO系列教程(十一) Pipe
Java NIO系列教程(十二) Java NIO与IO
Java NIO系列教程(十 五)Java NIO Path
然后下面我根据上面文章的学习自己实现了一个简单的基于NIO的Socket通信DEMO,期间踩了一个坑,运行期爆了java.lang.IllegalArgumentException错误,原来对于Socket服务端而言,SelectionKey没有OP_CONNECT状态,只能客户端说连接上了没有;对于客户端而言,OP_ACCEPT事件也是不存在的,因为只能服务端接收就绪,而我在服务端注册了OP_CONNECT事件,所以报错了。
(注意:以下示例并非最佳实现,只是为了模拟NIO的使用过程,我用了两个线程,一个当Client一个Server)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| import java.io.IOException; import java.net.InetAddress; 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 Main {
public static void main(String[] args) { new Thread(() -> { try { Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(new InetSocketAddress(8090)); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); SelectionKey key = null; for (;;) { int readyChannels = selector.select(); if (readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); while (it.hasNext()) { key = it.next(); if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = server.accept(); socketChannel.write(ByteBuffer.wrap("welcome".getBytes())); } it.remove(); } break; } selector.close(); serverSocketChannel.close(); } catch (IOException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress(InetAddress.getLocalHost(), 8090)); socketChannel.configureBlocking(false); Selector selector = Selector.open(); socketChannel.register(selector, SelectionKey.OP_READ); SelectionKey key = null; for (;;) { int readyChannels = selector.select(); if (readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); while (it.hasNext()) { key = it.next(); if (key.isReadable()) { SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(10); client.read(buffer); String msg = new String(buffer.array()).trim(); System.out.println("收到服务器响应:" + msg); } it.remove(); } break; } selector.close(); socketChannel.close(); } catch (IOException e) { e.printStackTrace(); } }).start(); } }
|
输出:
收到服务器响应:welcome