Bio Nio demo
BIO:
1 public class BioServer { 2 3 4 @SuppressWarnings("all") 5 public static void main(String[] args) throws IOException { 6 7 ServerSocket serverSocket = new ServerSocket(8000); 8 9 new Thread(() -> { 10 try { 11 Socket socket = serverSocket.accept(); 12 13 new Thread(() -> { 14 byte[] data = new byte[1024]; 15 try { 16 InputStream inputStream = socket.getInputStream(); 17 while (true) { 18 int len; 19 while ((len = inputStream.read(data)) != -1) { 20 System.out.println(new String(data, 0, len)); 21 } 22 } 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 }).start(); 27 } catch (IOException e) { 28 e.printStackTrace(); 29 } 30 }).start(); 31 32 } 33 34 35 }
1 public class BioClient { 2 3 4 @SuppressWarnings("all") 5 public static void main(String[] args) { 6 7 new Thread(() -> { 8 try { 9 Socket socket = new Socket("127.0.0.1", 8000); 10 while (true) { 11 socket.getOutputStream().write((new Date() + ": hello world ").getBytes()); 12 socket.getOutputStream().flush(); 13 Thread.sleep(2000); 14 } 15 } catch (IOException | InterruptedException e) { 16 e.printStackTrace(); 17 } 18 }).start(); 19 20 21 } 22 }
result:
Tue Sep 15 14:54:19 CST 2020: hello world
Tue Sep 15 14:54:21 CST 2020: hello world
Tue Sep 15 14:54:23 CST 2020: hello world
Tue Sep 15 14:54:25 CST 2020: hello world
Tue Sep 15 14:54:27 CST 2020: hello world
Tue Sep 15 14:54:29 CST 2020: hello world
Tue Sep 15 14:54:31 CST 2020: hello world
Tue Sep 15 14:54:33 CST 2020: hello world
NIO:
1 public class NIOServer { 2 3 /** 4 * serverSelector负责轮询是否有新的连接,clientSelector负责轮询连接是否有数据可读. 5 * 服务端监测到新的连接不再创建一个新的线程,而是直接将新连接绑定到clientSelector上,这样不用IO模型中1w个while循环在死等 6 * clientSelector被一个while死循环包裹,如果在某一时刻有多条连接有数据可读通过 clientSelector.select(1)方法轮询出来进而批量处理 7 * 数据的读写以内存块为单位 8 * 9 * @param args 10 * @throws IOException 11 */ 12 public static void main(String[] args) throws IOException { 13 Selector serverSelector = Selector.open(); 14 Selector clientSelector = Selector.open(); 15 16 new Thread(() -> { 17 try { 18 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 19 serverSocketChannel.socket().bind(new InetSocketAddress(8000)); 20 serverSocketChannel.configureBlocking(false); 21 serverSocketChannel.register(serverSelector, SelectionKey.OP_ACCEPT); 22 23 while (true) { 24 // 轮询监测是否有新的连接 25 if (serverSelector.select(1) > 0) { 26 Set<SelectionKey> selectionKeys = serverSelector.selectedKeys(); 27 Iterator<SelectionKey> keyIterator = selectionKeys.iterator(); 28 while (keyIterator.hasNext()) { 29 SelectionKey selectionKey = keyIterator.next(); 30 if (selectionKey.isAcceptable()) { 31 try { 32 //(1)每来一个新连接不需要创建一个线程而是直接注册到clientSelector 33 SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept(); 34 socketChannel.configureBlocking(false); 35 socketChannel.register(clientSelector, SelectionKey.OP_READ); 36 } finally { 37 keyIterator.remove(); 38 } 39 } 40 } 41 } 42 } 43 } catch (IOException e) { 44 e.printStackTrace(); 45 } 46 }).start(); 47 48 new Thread(() -> { 49 try { 50 while (true) { 51 // (2)批量轮询是否有哪些连接有数据可读 52 if (clientSelector.select(1) > 0) { 53 Set<SelectionKey> selectionKeys = serverSelector.selectedKeys(); 54 Iterator<SelectionKey> keyIterator = selectionKeys.iterator(); 55 while (keyIterator.hasNext()) { 56 SelectionKey selectionKey = keyIterator.next(); 57 if (selectionKey.isReadable()) { 58 try { 59 SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); 60 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); 61 //(3)读取数据以块为单位批量读取 62 socketChannel.read(byteBuffer); 63 byteBuffer.flip(); 64 System.out.println(Charset.defaultCharset().newDecoder().decode(byteBuffer) 65 .toString()); 66 } finally { 67 keyIterator.remove(); 68 selectionKey.interestOps(SelectionKey.OP_READ); 69 } 70 } 71 } 72 } 73 } 74 } catch (IOException e) { 75 e.printStackTrace(); 76 } 77 }).start(); 78 } 79 }