代碼轉自 https://www.jianshu.com/p/a9d030fec081java
服務端:緩存
package nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class Server { private Selector selector; private ByteBuffer readBuffer = ByteBuffer.allocate(1024);//調整緩存的大小能夠看到打印輸出的變化 private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);//調整緩存的大小能夠看到打印輸出的變化 String str; public void start() throws IOException { // 打開服務器套接字通道 ServerSocketChannel ssc = ServerSocketChannel.open(); // 服務器配置爲非阻塞 ssc.configureBlocking(false); // 進行服務的綁定 ssc.bind(new InetSocketAddress("localhost", 8001)); // 經過open()方法找到Selector selector = Selector.open(); // 註冊到selector,等待鏈接 ssc.register(selector, SelectionKey.OP_ACCEPT); while (!Thread.currentThread().isInterrupted()) { selector.select(); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = keys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (!key.isValid()) { continue; } if (key.isAcceptable()) { accept(key); } else if (key.isReadable()) { read(key); } else if (key.isWritable()) { write(key); } keyIterator.remove(); //該事件已經處理,能夠丟棄 } } } private void write(SelectionKey key) throws IOException, ClosedChannelException { SocketChannel channel = (SocketChannel) key.channel(); System.out.println("write:"+str); sendBuffer.clear(); sendBuffer.put(str.getBytes()); sendBuffer.flip(); channel.write(sendBuffer); channel.register(selector, SelectionKey.OP_READ); } private void read(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); // Clear out our read buffer so it's ready for new data this.readBuffer.clear(); // readBuffer.flip(); // Attempt to read off the channel int numRead; try { numRead = socketChannel.read(this.readBuffer); } catch (IOException e) { // The remote forcibly closed the connection, cancel // the selection key and close the channel. key.cancel(); socketChannel.close(); return; } str = new String(readBuffer.array(), 0, numRead); System.out.println(str); socketChannel.register(selector, SelectionKey.OP_WRITE); } private void accept(SelectionKey key) throws IOException { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel clientChannel = ssc.accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ); System.out.println("a new client connected "+clientChannel.getRemoteAddress()); } public static void main(String[] args) throws IOException { System.out.println("server started..."); new Server().start(); } } 做者:御風逍遙 連接:https://www.jianshu.com/p/a9d030fec081 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
客戶端:服務器
package 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.Scanner; import java.util.Set; public class Client { ByteBuffer writeBuffer = ByteBuffer.allocate(1024); ByteBuffer readBuffer = ByteBuffer.allocate(1024); public void start() throws IOException { // 打開socket通道 SocketChannel sc = SocketChannel.open(); //設置爲非阻塞 sc.configureBlocking(false); //鏈接服務器地址和端口 sc.connect(new InetSocketAddress("localhost", 8001)); //打開選擇器 Selector selector = Selector.open(); //註冊鏈接服務器socket的動做 sc.register(selector, SelectionKey.OP_CONNECT); Scanner scanner = new Scanner(System.in); while (true) { //選擇一組鍵,其相應的通道已爲 I/O 操做準備就緒。 //此方法執行處於阻塞模式的選擇操做。 selector.select(); //返回此選擇器的已選擇鍵集。 Set<SelectionKey> keys = selector.selectedKeys(); System.out.println("keys=" + keys.size()); Iterator<SelectionKey> keyIterator = keys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); keyIterator.remove(); // 判斷此通道上是否正在進行鏈接操做。 if (key.isConnectable()) { sc.finishConnect(); sc.register(selector, SelectionKey.OP_WRITE); System.out.println("server connected..."); break; } else if (key.isWritable()) { //寫數據 System.out.print("please input message:"); String message = scanner.nextLine(); //ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes()); writeBuffer.clear(); writeBuffer.put(message.getBytes()); //將緩衝區各標誌復位,由於向裏面put了數據標誌被改變要想從中讀取數據發向服務器,就要復位 writeBuffer.flip(); sc.write(writeBuffer); //註冊寫操做,每一個chanel只能註冊一個操做,最後註冊的一個生效 //若是你對不止一種事件感興趣,那麼能夠用「位或」操做符將常量鏈接起來 //int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; //使用interest集合 sc.register(selector, SelectionKey.OP_READ); sc.register(selector, SelectionKey.OP_WRITE); sc.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()){//讀取數據 System.out.print("receive message:"); SocketChannel client = (SocketChannel) key.channel(); //將緩衝區清空以備下次讀取 readBuffer.clear(); int num = client.read(readBuffer); System.out.println(new String(readBuffer.array(),0, num)); //註冊讀操做,下一次讀取 sc.register(selector, SelectionKey.OP_WRITE); } } } } public static void main(String[] args) throws IOException { new Client().start(); } } 做者:御風逍遙 連接:https://www.jianshu.com/p/a9d030fec081 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。