[转]用nio实现Echo服务
[转]http://finux.iteye.com/blog/368955
?
今天突然间想用nio实现个Echo服务,程序实现起来实现不算困难,但跑起来后,在Server端的ServerSocket完成accept之后,我的CPU总是跳到100%。嗯,小郁闷,后来,才发现自己在Server端注册了多余的监听事件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;//缓冲区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("读取的内容为:" + 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也可以像下面这样来实现:
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中读取内容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);}}?