NIO经典demo源码 发表于 2018-02-21 server:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194package com.test.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.ByteBuffer;import java.nio.channels.*;import java.util.Iterator;import java.util.Set;/** * Created by lifei on 16/11/8. */public class NIOServer { private int flag = 0;/*标识数字*/ private int blockSize = 4096;/*缓冲区大小*/ private ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);/*接受数据缓冲区*/ private ByteBuffer receiveBuffer = ByteBuffer.allocate(blockSize);/*发送数据缓冲区*/ private Selector selector; public NIOServer(int port) { try { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 打开服务器套接字通道 serverSocketChannel.configureBlocking(false);//// 服务器配置为非阻塞 ServerSocket serverSocket = serverSocketChannel.socket(); // 检索与此通道关联的服务器套接字 serverSocket.bind(new InetSocketAddress(port));//绑定ip和端口 selector = Selector.open();//打开选择器 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 注册到selector,等待连接 System.out.println("Server start -> " + port); } catch (IOException e) { e.printStackTrace(); } } //监听 public void listen(){ while (true){ try { selector.select();//如果查询不到,会阻塞 选择一组键,并且相应的通道已经打开 Set<SelectionKey> selectionKeys = selector.selectedKeys();// 返回此选择器的已选择键集。 Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()){ SelectionKey selectionKey = iterator.next(); iterator.remove(); //业务逻辑 handleKey(selectionKey); } } catch (IOException e) { e.printStackTrace(); } } } // 处理请求 public void handleKey(SelectionKey selectionKey){ try { // 接受请求 ServerSocketChannel server; SocketChannel client; String receiveText; String sendText; int count; if (selectionKey.isAcceptable()){// 测试此键的通道是否已准备好接受新的套接字连接。 server = (ServerSocketChannel) selectionKey.channel();// 返回为之创建此键的通道。 client = server.accept();// 接受到此通道套接字的连接。 此方法返回的套接字通道(如果有)将处于阻塞模式。 client.configureBlocking(false);// 配置为非阻塞 client.register(selector,SelectionKey.OP_READ);// 注册到selector,等待连接 } else if (selectionKey.isReadable()){ client = (SocketChannel) selectionKey.channel();// 返回为之创建此键的通道。 receiveBuffer.clear();//todo 将缓冲区清空以备下次读取 count = client.read(receiveBuffer);//读取服务器发送来的数据到缓冲区中 if (count > 0){ receiveText = new String(receiveBuffer.array(),0,count); System.out.println("服务端接收到客户端的信息:"+receiveText); client.register(selector,SelectionKey.OP_WRITE); } } else if (selectionKey.isWritable()){ sendBuffer.clear();//将缓冲区清空以备下次写入 client = (SocketChannel) selectionKey.channel();// 返回为之创建此键的通道。 sendText = "msg send to clent ..."+(flag++);//发送的数据 sendBuffer.put(sendText.getBytes());//向缓冲区中输入数据 sendBuffer.flip();//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 client.write(sendBuffer);//输出到通道 System.out.println("服务端发送数据给客户端:"+sendText); client.register(selector,SelectionKey.OP_READ); } } catch (Exception e){ e.printStackTrace(); } } public static void main(String[] args) { int port = 7080; NIOServer server = new NIOServer(port); server.listen(); }}``` # client: ```javapackage com.test.nio;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.SocketChannel;import java.util.Iterator;import java.util.Set;/** * Created by lifei on 16/11/8. * http://developer.51cto.com/art/201112/307685.htm */public class NIOClient { private static int flag = 0;/*标识数字*/ private static int blockSize = 4096;/*缓冲区大小*/ private static ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);/*接受数据缓冲区*/ private static ByteBuffer receiveBuffer = ByteBuffer.allocate(blockSize); /*服务器端地址*/ private final static InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1",7080); public static void main(String[] args) { try { SocketChannel socketChannel = SocketChannel.open();// 打开socket通道 socketChannel.configureBlocking(false);// 设置为非阻塞方式 Selector selector = Selector.open();//打开选择器 socketChannel.register(selector, SelectionKey.OP_CONNECT);// 注册连接服务端socket动作 socketChannel.connect(serverAddress);// 连接 // 分配缓冲区大小内存 Set<SelectionKey> selectionKeys; Iterator<SelectionKey> iterator; SelectionKey selectionKey; SocketChannel client; String receiveText; String sendText; int count; while (true){ try { selector.select();//todo 选择一组键,其相应的通道已为 I/O 操作准备就绪。 此方法执行处于阻塞模式的选择操作。 selectionKeys = selector.selectedKeys();//返回此选择器的已选择键集。 iterator = selectionKeys.iterator(); while (iterator.hasNext()){ selectionKey = iterator.next(); if (selectionKey.isConnectable()){ System.out.println("client connet"); client = (SocketChannel) selectionKey.channel(); if (client.isConnectionPending()){// 判断此通道上是否正在进行连接操作。 完成套接字通道的连接过程。 client.finishConnect(); System.out.println("客户端完成连接操作"); sendBuffer.clear(); sendText = "Hello server..."; sendBuffer.put(sendText.getBytes()); sendBuffer.flip(); client.write(sendBuffer); } client.register(selector,SelectionKey.OP_READ); } else if (selectionKey.isReadable()){ client = (SocketChannel) selectionKey.channel(); receiveBuffer.clear();//将缓冲区清空以备下次读取 count = client.read(receiveBuffer);//读取服务器发送来的数据到缓冲区中 if (count > 0){ receiveText = new String(receiveBuffer.array(),0,count); System.out.println("客户端接收到服务端数据:"+receiveText); client.register(selector,SelectionKey.OP_WRITE); } } else if (selectionKey.isWritable()){ sendBuffer.clear(); client = (SocketChannel) selectionKey.channel(); sendText = "Msg to server ..."+(flag++); sendBuffer.put(sendText.getBytes()); sendBuffer.flip();//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 client.write(sendBuffer); System.out.println("客户端发送数据给服务端"+sendText); client.register(selector,SelectionKey.OP_READ); } } selectionKeys.clear(); } catch (Exception e){ } } } catch (IOException e) { e.printStackTrace(); } }}