標籤:
分別使用Java IO、Java NIO、Netty來實現一個簡單的EchoServer(即原樣返回用戶端的輸入資訊)。
Java IO
int port = 9000;ServerSocket ss = new ServerSocket(port);while (true) {final Socket socket = ss.accept();new Thread(new Runnable() {public void run() {while (true) {try {BufferedInputStream in = new BufferedInputStream(socket.getInputStream());byte[] buf = new byte[1024];int len = in.read(buf); // read message from clientString message = new String(buf, 0, len);BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());out.write(message.getBytes()); // echo to clientout.flush();} catch (IOException e) {e.printStackTrace();}}}}).start();}
實際效果用telnet來示範,如下所示:
$ telnet 127.0.0.1 9000Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is ‘^]‘.hihi你好你好
java io缺點:
需要為每個用戶端串連建立一個線程。
Java NIO
ServerSocketChannel ssChannel = ServerSocketChannel.open();int port = 9001;ssChannel.bind(new InetSocketAddress(port));Selector selector = Selector.open();ssChannel.configureBlocking(false);ssChannel.register(selector, SelectionKey.OP_ACCEPT); //註冊監聽串連請求while (true) {selector.select();//阻塞 直到某個channel註冊的事件被觸發Set<SelectionKey> keys = selector.selectedKeys();for (SelectionKey key : keys) {if (key.isAcceptable()) { //用戶端串連請求ServerSocketChannel ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();sc.configureBlocking(false);sc.register(selector, SelectionKey.OP_READ); //註冊監聽用戶端輸入}if(key.isReadable()){ //用戶端輸入SocketChannel sc = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);sc.read(buffer);buffer.flip();sc.write(buffer);}}keys.clear();}
優點:
事件驅動 可通過一個線程來管理多個串連(channel)
但要注意 並不是任何情境都是NIO優於IO的。
Netty
public class NettyEchoServer {public class EchoServerHandler extends ChannelHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) { //ehco to clientctx.write(msg);ctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {// Close the connection when an exception is raised.cause.printStackTrace();ctx.close();}}private int port;public NettyEchoServer(int port) {this.port = port;}public void run() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() { @Overridepublic void initChannel(SocketChannel ch)throws Exception {ch.pipeline().addLast(new EchoServerHandler());}}).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); // Bind and start to accept incoming connections.ChannelFuture f = b.bind(port).sync(); // Wait until the server socket is closed.// In this example, this does not happen, but you can do that to gracefully shut down your server.f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 9002;new NettyEchoServer(port).run();}}
上例摘自官方文檔。
優點:
似乎僅需要繼承ChannelHandlerAdapter, 然後覆蓋相應方法即可。
參考文檔:
http://en.wikipedia.org/wiki/Non-blocking_I/O_(Java)
https://today.java.net/pub/a/today/2007/02/13/architecture-of-highly-scalable-nio-server.html
http://www.javaworld.com/article/2078654/java-se/java-se-five-ways-to-maximize-java-nio-and-nio-2.html
http://netty.io/wiki/user-guide-for-5.x.html
分別使用Java IO、NIO、Netty實現的一個Echo Server樣本