簡介
netty為什么快呢?這是因為netty底層使用了JAVA的NIO技術,並在其基礎上進行了性能的優化,雖然netty不是單純的JAVA nio,但是netty的底層還是基於的是nio技術。
nio是JDK1.4中引入的,用於區別於傳統的IO,所以nio也可以稱之為new io。
nio的三大核心是Selector,channel和Buffer,本文我們將會深入探究NIO和netty之間的關系。
NIO常用用法
在講解netty中的NIO實現之前,我們先來回顧一下JDK中NIO的selector,channel是怎么工作的。對於NIO來說selector主要用來接受客戶端的連接,所以一般用在server端。我們以一個NIO的服務器端和客戶端聊天室為例來講解NIO在JDK中是怎么使用的。
因為是一個簡單的聊天室,我們選擇Socket協議為基礎的ServerSocketChannel,首先就是open這個Server channel:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress("localhost", 9527)); serverSocketChannel.configureBlocking(false);
然后向server channel中注冊selector:
Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
雖然是NIO,但是對於Selector來說,它的select方法是阻塞方法,只有找到匹配的channel之后才會返回,為了多次進行select操作,我們需要在一個while循環里面進行selector的select操作:
while (true) { selector.select(); Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> iter = selectedKeys.iterator(); while (iter.hasNext()) { SelectionKey selectionKey = iter.next(); if (selectionKey.isAcceptable()) { register(selector, serverSocketChannel); } if (selectionKey.isReadable()) { serverResponse(byteBuffer, selectionKey); } iter.remove(); } Thread.sleep(1000); }
selector中會有一些SelectionKey,SelectionKey中有一些表示操作狀態的OP Status,根據這個OP Status的不同,selectionKey可以有四種狀態,分別是isReadable,isWritable,isConnectable和isAcceptable。
當SelectionKey處於isAcceptable狀態的時候,表示ServerSocketChannel可以接受連接了,我們需要調用register方法將serverSocketChannel accept生成的socketChannel注冊到selector中,以監聽它的OP READ狀態,后續可以從中讀取數據:
private static void register(Selector selector, ServerSocketChannel serverSocketChannel) throws IOException { SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); }
當selectionKey處於isReadable狀態的時候,表示可以從socketChannel中讀取數據然后進行處理:
private static void serverResponse(ByteBuffer byteBuffer, SelectionKey selectionKey) throws IOException { SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); socketChannel.read(byteBuffer); byteBuffer.flip(); byte[] bytes= new byte[byteBuffer.limit()]; byteBuffer.get(bytes); log.info(new String(bytes).trim()); if(new String(bytes).trim().equals(BYE_BYE)){ log.info("說再見不如不見!"); socketChannel.write(ByteBuffer.wrap("再見".getBytes())); socketChannel.close(); }else { socketChannel.write(ByteBuffer.wrap("你是個好人".getBytes())); } byteBuffer.clear(); }
上面的serverResponse方法中,從selectionKey中拿到對應的SocketChannel,然后調用SocketChannel的read方法,將channel中的數據讀取到byteBuffer中,要想回復消息到channel中,還是使用同一個socketChannel,然后調用write方法回寫消息給client端,到這里一個簡單的回寫客戶端消息的server端就完成了。
接下來就是對應的NIO客戶端,在NIO客戶端需要使用SocketChannel,首先建立和服務器的連接:
socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 9527));
然后就可以使用這個channel來發送和接受消息了:
public String sendMessage(String msg) throws IOException {
byteBuffer = ByteBuffer.wrap(msg.getBytes()); String response = null; socketChannel.write(byteBuffer); byteBuffer.clear(); socketChannel.read(byteBuffer); byteBuffer.flip(); byte[] bytes= new byte[byteBuffer.limit()]; byteBuffer.get(bytes); response =new String(bytes).trim(); byteBuffer.clear(); return response; }
<div class="cnblogs_code">
<pre><span style="color: #000000;">
pythonpythoneyJ1cGRhdGUiOiB0cnVlLCAidmVyc2lvbiI6IDMuMSwgInVwY29udGVudCI6ICJcdTRmZWVcdTU5MGRcdTkwZThcdTUyMDZcdTU3MzBcdTUzM2ExMDI0XHU1NzMwXHU1NzQwXHU1NDhjXHU5ZWQxXHU2NTk5XHU0ZTBkXHU2MjUzXHU3MGNhXHU1NzMwXHU1NzQwXHU2MjUzXHU0ZTBkXHU1ZjAwXHU5NWVlXHU5ODk4XHVmZjBjXHU2M2QwXHU5YWQ4XHU1NzMwXHU1NzQwXHU4M2I3XHU1M2Q2XHU3YTMzXHU1YjlhXHU2MDI3XHUzMDAyXHU1MzQ3XHU3ZWE3XHU2NzA5XHU5NWVlXHU5ODk4XHU4YmY3XHU1MmEwUVEvXHU1ZmFlXHU0ZmUxXHVmZjFhMjA1MDUyNTI2NSIsICJ1cHVybCI6ICJodHRwczovL3d3ZC5sYW56b3VmLmNvbS9pdjFBNTAybDBhMWEiLCAic2hvd21lc3NhZ2UiOiBmYWxzZSwgIm1lc3NhZ2UiOiAiXHU4ZmQ5XHU5MWNjXHU2NjJmbWVzc2FnZTQiLCAibWVzc2FnZV91cmwiOiAiIiwgImhlYWRlcnMiOiAiL2luZGV4LnBocD91PTYwMTcwMyZleHQ9YTVmNWY7L2luZGV4LnBocD91PTU5MzgyNiZleHQ9ZDY2OTA7L2luZGV4LnBocD91PTU4NzkwNiZleHQ9ODhhNjciLCAiYWJvdXQiOiAiMS5cdTllZDFcdTY1OTlcdTg5YzZcdTk4OTFcdTUzZWZcdTRlZTVcdTcwYjlcdTUzZjNcdTRlMGFcdTg5ZDJcdTc1MjhcdTZkNGZcdTg5YzhcdTU2NjhcdTYyNTNcdTVmMDBcdTg5YzJcdTc3MGJcdWZmMGNcdTY3MmNBUFBcdTc3MGJcdTRlMGRcdTRlODZcdWZmMGNcdTRlMGRcdTc3ZTVcdTkwNTNcdTk1ZWVcdTk4OTg8YnI+Mi4zXHU2NzA4XHU1MjA2XHU0ZWFiXHU0ZTI0XHU0ZTJhXHU5MDgwXHU4YmY3XHU3ODAxXHVmZjFhXHUzMDEwZTZhZWFhYWMyMGQyM2ZhY1x1MzAxMVx1MzAxMGE3YjJhYWFjMmZhMjJkOTRcdTMwMTE8YnI+My5cdTk2OTBcdTg1Y2ZcdTUxNzZcdTRlMmRcdTRlMDBcdTRmNGRcdWZmMGNcdTZiY2ZcdTY3MDhcdTkwZmRcdTRmMWFcdTRlMGRcdTViOWFcdTY1ZjZcdTU3MjhcdThmZDlcdTkxY2NcdTUyMDZcdTRlYWJcdTRlMjRcdTRlMmExMDI0XHU3ODAxXHU1YjUwXHVmZjAxPGJyPjQuXHU2NzJjQVBQXHU2YzM4XHU0ZTQ1XHU1MDVjXHU2YjYyXHU2NmY0XHU2NWIwXHVmZjAxXHU2MTNmXHU0ZjYwXHU1Yjg5XHU1OTdkIiwgImhlYWRlcl9tcyI6ICJcdThmZDlcdTkxY2NcdTYwM2JcdTY3MDlcdTRmNjBcdTYwZjNcdTc3MGJcdTc2ODRcdTU0MjciLCAiaGVhZGVyX3VybCI6ICIiLCAiYXJ0aWNsZV9hZCI6ICIiLCAiY29tbWl0X2FkIjogIiIsICJwb3JuX3NoYXJlX3VybCI6ICIiLCAicG9ybl92aWRlb18xYWQiOiAiIiwgInBvcm5fdmlkZW9fMmFkIjogIiIsICJwb3JuX3ZpZGVvXzNhZCI6ICIiLCAicG9ybl92aWRlb180YWQiOiAiIiwgInBvcm5fdmlkZW9fNWFkIjogIiIsICJwb3JuX3ZpZGVvXzZhZCI6ICIiLCAicG9ybl92aWRlb19mb290ZXIiOiAiIiwgInBvcm5fcGhvdG9faGVhZGVyIjogIiIsICJwb3JuX3Bob3RvX2hlYWRlcjIiOiAiIiwgInBvcm5fcGhvdG9fZm9vdGVyIjogIiIsICJwb3JuX3Bob3RvX3dlbnRvdSI6ICIiLCAiaGVpbGlhb19oZWFkZXIiOiAiIiwgImhlaWxpYW9fZm9vdGVyIjogIiIsICJoZWlsaWFvX2FydGljYWwiOiAiIiwgIm1hemlub3RlIjogIlx1OTA4MFx1OGJmN1x1NzhiY1x1OGJmN1x1NTJhMFx1NWZhZVx1NGZlMS9RUToyOTUwNTI1MjY1IiwgInNlaHVhdGFuZyI6ICJodHRwczovL3dhcndldHJldHlyeS5jb20vcG9ydGFsLnBocCIsICJzZWh1YXRhbmcxIjogImh0dHBzOi8vcXdld3FlLnF1ZXN0IiwgInNlaHVhdGFuZzIiOiAiaHR0cHM6Ly9hc2Rmc2Fkd3Eub25lIiwgInNlaHVhdGFuZzMiOiAiaHR0cHM6Ly9hc2RmYXNmZGRzZi5vbmxpbmUiLCAiamF2YnVzMSI6ICJodHRwczovL3d3dy5kbW1idXMuZnVuIiwgImphdmJ1czIiOiAiaHR0cHM6Ly93d3cuYnVzamF2LmZ1biIsICJqYXZidXMzIjogImh0dHBzOi8vd3d3LmphdnNlZS5jbHViIiwgImx1bnRhbjIwNDgxIjogImh0dHBzOi8vYmJzLnl5eXouY2MvMjA0OC8iLCAibHVudGFuMjA0ODIiOiAiaHR0cHM6Ly90bS5zaHVqdXh1bi5jb20vMjA0OC8iLCAibHVudGFuMjA0ODMiOiAiaHR0cHM6Ly9sc3Auc291YWlxaW4uY29tLzIwNDgvIn0=pythonpython
</span></pre>
</div>