您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么用nio實現(xiàn)Echo服務”,在日常操作中,相信很多人在怎么用nio實現(xiàn)Echo服務問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么用nio實現(xiàn)Echo服務”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
今天突然間想用nio實現(xiàn)個Echo服務,程序?qū)崿F(xiàn)起來實現(xiàn)不算困難,但跑起來后,在Server端的ServerSocket完成accept之后,我的CPU總是跳到100%。嗯,小郁悶,后來,才發(fā)現(xiàn)自己在Server端注冊了多余的監(jiān)聽事件SelectionKey.OP_WRITE,改過來后好多了,希望記住這個教訓。
EchoServer.java
package edu.dlut.zxf.nio; 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.Set; /** * Echo服務器 * @author finux */ public class EchoServer { public final static int BUFFER_SIZE = 1024; //默認端口 public final static String HOST = "210.30.107.17"; public final static int PORT = 8888; public static void main(String[] args) { ServerSocketChannel ssc = null; //緩沖區(qū) ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); Selector selector = null; try { selector = Selector.open(); ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(InetAddress.getByName(HOST), PORT)); ssc.configureBlocking(false); ssc.register(selector, SelectionKey.OP_ACCEPT); print("服務器啟動,準備好連接..."); while (selector.select() > 0) { Set<SelectionKey> selectionKeys = selector.selectedKeys(); for (SelectionKey key: selectionKeys) { if (key.isAcceptable()) { SocketChannel sc = ssc.accept(); print("有新的連接!地址:" + sc.socket().getRemoteSocketAddress()); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_READ); // 不要寫成: // sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); // 畢竟這樣多注冊的無用的事件SelectionKey.OP_WRTE // 如果是這樣,在完成accept后,CPU也許會跑到100% } //same to if ((ops & SelectionKey.OP_READ) == SelectionKey.OP_READ) { if (key.isReadable()) { SocketChannel sc = (SocketChannel)key.channel(); print("有新的讀??!地址:" + sc.socket().getRemoteSocketAddress()); buffer.clear(); sc.read(buffer); buffer.flip(); byte[] b = new byte[buffer.limit()]; buffer.get(b); String s = new String(b); if (s.equals("bye")) { print("斷開連接:" + sc.socket().getRemoteSocketAddress()); //斷開連接后,取消此鍵的通道到其選擇器的注冊 key.cancel(); sc.close(); continue; } print("讀取的內(nèi)容為:" + s); buffer.clear(); s = "echo: " + s; buffer.put(s.getBytes()); buffer.flip(); sc.write(buffer); } } selectionKeys.clear(); } } catch(IOException e) { e.printStackTrace(); } } private static void print(String s) { System.out.println(s); } }
EchoClient.java
package edu.dlut.zxf.nio; import java.util.Set; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; /** * Echo客戶端 * @author finux */ public class EchoClient { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(EchoServer.BUFFER_SIZE); Selector selector = null; SocketChannel sc = null; try { selector = Selector.open(); sc = SocketChannel.open(); sc.configureBlocking(false); sc.connect(new InetSocketAddress(InetAddress.getByName(EchoServer.HOST), EchoServer.PORT)); print("客戶端啟動,準備連接..."); if (sc.isConnectionPending()) { sc.finishConnect(); } print("完成連接"); sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); boolean writed = false; boolean down = false; while (!down && selector.select() > 0) { Set<SelectionKey> selectionKeys = selector.selectedKeys(); for (SelectionKey key: selectionKeys) { //int ops = key.readyOps(); //if ((ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE && !writed) { if (key.isWritable() && !writed) { System.out.print("Input(bye to end): "); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String s = br.readLine(); if (s != null && !s.trim().equals("")) { buffer.clear(); buffer.put(s.getBytes()); buffer.flip(); sc.write(buffer); writed = true; if (s.equals("bye")) { down = true; break; } } } //if ((ops & SelectionKey.OP_READ) == SelectionKey.OP_READ && writed) { if (key.isReadable() && writed) { buffer.clear(); sc.read(buffer); buffer.flip(); byte[] b = new byte[buffer.limit()]; buffer.get(b); print(new String(b)); writed = false; } } selectionKeys.clear(); } } catch(IOException e) { e.printStackTrace(); } } private static void print(String s) { System.out.println(s); } }
當然EchoClient也可以像下面這樣來實現(xiàn):
EchoClient2.java
package edu.dlut.zxf.nio; import java.util.Set; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; /** * Echo客戶端2 * @author finux */ public class EchoClient2 { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(EchoServer.BUFFER_SIZE); Selector selector = null; SocketChannel sc = null; try { selector = Selector.open(); sc = SocketChannel.open(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_CONNECT); sc.connect(new InetSocketAddress(InetAddress.getByName(EchoServer.HOST), EchoServer.PORT)); print("客戶端啟動,準備連接..."); boolean writed = false; boolean down = false; while (!down && selector.select() > 0) { Set<SelectionKey> selectionKeys = selector.selectedKeys(); for (SelectionKey key: selectionKeys) { //int ops = key.readyOps(); //if ((ops & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) { if (key.isConnectable()) { print("完成連接!"); if (sc.isConnectionPending()) { sc.finishConnect(); } sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); } //if ((ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE && !writed) { if (key.isWritable() && !writed) { //從準備IO中讀取內(nèi)容 System.out.print("Input(bye to end): "); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String s = br.readLine(); if (s != null && !s.trim().equals("")) { buffer.clear(); buffer.put(s.getBytes()); buffer.flip(); sc.write(buffer); writed = true; if (s.equals("bye")) { down = true; break; } } } //if ((ops & SelectionKey.OP_READ) == SelectionKey.OP_READ && writed) { if (key.isReadable() && writed) { buffer.clear(); sc.read(buffer); buffer.flip(); byte[] b = new byte[buffer.limit()]; buffer.get(b); print(new String(b)); writed = false; } } selectionKeys.clear(); } } catch(IOException e) { e.printStackTrace(); } } private static void print(String s) { System.out.println(s); } }
但是這樣的話,顯然EchoClient2中的while循環(huán)中的for循環(huán)(若有n次),在每次循環(huán)中都會多出n-1次if判斷,就是下面這個:
if (key.isConnectable()) {
到此,關(guān)于“怎么用nio實現(xiàn)Echo服務”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。